public async Task <IActionResult> SubmitTokenInput(TokenInputViewModel model) { if (!ModelState.IsValid || String.IsNullOrWhiteSpace(model.Email) || String.IsNullOrWhiteSpace(model.Purpose) || String.IsNullOrWhiteSpace(model.Token)) { return(View(model)); } var email = _userManager.NormalizeKey(model.Email); model.Token = model.Token.Replace(" ", ""); var userWithConfirmedEmail = await _userManager.FindByLoginAsync("Email", email); var userCurrentlySignedIn = await _userManager.GetUserAsync(User); var userEmpty = new ApplicationUser() { Id = email, Email = email, SecurityStamp = TemporarySecurityStamp }; var isTokenValid = false; if (model.Purpose == "RegisterOrLogin") // Trying to register or login { await _signInManager.SignOutAsync(); isTokenValid = await _userManager.VerifyUserTokenAsync( userWithConfirmedEmail // Case: logging-in ?? userEmpty, // Case: registering, "Email", model.Purpose, model.Token); } else // Trying to add email { if (userCurrentlySignedIn == null) // If the user is not signed in, prompt them to, with the return url leading back here { return(RedirectToAction(nameof(Login), new { returnUrl = Request.Path + Request.QueryString })); } isTokenValid = await _userManager.VerifyUserTokenAsync( userCurrentlySignedIn, "Email", model.Purpose, model.Token); } if (!isTokenValid) { _notice.AddErrors(ModelState, "Error validating code, it might have expired. Please try again!"); return(View(model)); } // Invalidates all tokens for user when trying to login or add login // Note: this also invalidates any attempts to add more logins than allowed if ((userCurrentlySignedIn ?? userWithConfirmedEmail) != null) { var updateSecStampResult = await _userManager.UpdateSecurityStampAsync(userCurrentlySignedIn ?? userWithConfirmedEmail); if (!updateSecStampResult.Succeeded) { _notice.AddErrors(ModelState); return(View(model)); } } // Valid {token + email (user) + purpose} supplied if (model.Purpose == "RegisterOrLogin") // Trying to register or login { if (userWithConfirmedEmail == null) // Success trying to register { var token = await _userManager.GenerateUserTokenAsync(userEmpty, "Default", "Register"); return(View(nameof(Register), new RegisterViewModel { RememberMe = model.RememberMe, Email = email, UserName = GenerateUserName(email), Token = token, ReturnUrl = model.ReturnUrl })); } else // Success trying to login { await _events.AddEvent(AuthEventType.Login, JsonConvert.SerializeObject(new { LoginProvider = "Email", ProviderKey = model.Email }), userWithConfirmedEmail); await _signInManager.SignInAsync(userWithConfirmedEmail, isPersistent : model.RememberMe); } } else // Trying to add email { var userWithConfirmedEmailToAdd = await _userManager.FindByLoginAsync("Email", email); if (userWithConfirmedEmailToAdd == null) // Email to be added never seen before, add email to userCurrentlySignedIn { var addLoginResult = await _userManager.AddLoginAsync(userCurrentlySignedIn, new UserLoginInfo("Email", email, "Email")); if (!addLoginResult.Succeeded) { _notice.AddErrors(ModelState, addLoginResult); return(View(model)); } userCurrentlySignedIn.Email = email; userCurrentlySignedIn.EmailConfirmed = true; var updateUserResult = await _userManager.UpdateAsync(userCurrentlySignedIn); if (!updateUserResult.Succeeded) { _notice.AddErrors(ModelState, updateUserResult); return(View(model)); } await _events.AddEvent(AuthEventType.AddLogin, JsonConvert.SerializeObject(new { LoginProvider = "Email", ProviderKey = model.Email }), userCurrentlySignedIn); } else // Email to be added is in use { // Note: this area is unlikely to be reached since security stamp is changed once a login is added if (userWithConfirmedEmailToAdd.Id == userCurrentlySignedIn.Id) // Email is already in user's account { _notice.AddErrors(ModelState, "This email is already in your account."); return(View(model)); } else // Email associated with another account (same user since both verified!) { _notice.AddErrors(ModelState, "This email is in another user's account. Try logging in using that email instead."); return(View(model)); } } } // Success return(RedirectToLocal(model.ReturnUrl)); }
public static string TokenInputLink(this IUrlHelper urlHelper, string scheme, TokenInputViewModel tokenModel) { return(urlHelper.Action( action: nameof(AccountController.TokenInput), controller: "Account", values: tokenModel, protocol: scheme)); }
public IActionResult TokenInput(TokenInputViewModel model) { return(View(model)); }