public async Task <IActionResult> ExternalLoginCallback(ExternalLoginCallbackViewModel model) { if (!ModelState.IsValid) { throw new ValidationException(ModelState.GetValidationString()); } if (model.RemoteError != null) { string error = $"Error from external login: {model.RemoteError}"; logger.LogError(error); return(Redirect($"{model.ErrorUrl}?error=external-login&message={WebUtility.UrlEncode(error)}&returnUrl={model.ReturnUrl}")); } ExternalLoginInfo?info = await signInManager.GetExternalLoginInfoAsync().ConfigureAwait(false); if (info == null) { string error = $"Error from external login: unable to retrieve user data"; logger.LogError(error); return(Redirect($"{model.ErrorUrl}?error=external-userdata&message={WebUtility.UrlEncode(error)}&returnUrl={model.ReturnUrl}")); } // Sign in the user with this external login provider if the user already has a login. SignInResult result = await signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent : false).ConfigureAwait(false); if (result.Succeeded) { logger.LogInformation("User logged in with {0} provider.", info.LoginProvider); return(Redirect(model.ReturnUrl)); } else if (result.IsLockedOut) { logger.LogInformation("User is locked out"); return(Redirect($"{model.ErrorUrl}?error=lockout&message={WebUtility.UrlEncode("User is locked out")}&returnUrl={model.ReturnUrl}")); } // If the user can't login with the external login, create a new account or link one string email = info.Principal.FindFirstValue(ClaimTypes.Email); ExternalUserResult newUserResult = await userService.CreateOrAddExternalToUser(email, info).ConfigureAwait(false); if (newUserResult.Result.Succeeded) { if (newUserResult.AddedUser) { return(Redirect(model.FinishRegistrationUrl)); } else { return(Redirect(model.ReturnUrl)); } } else { string error = string.Join(", ", newUserResult.Result.Errors.Select(e => e.Description)); logger.LogError(error); return(Redirect($"{model.ErrorUrl}?error=external-login-create&message={WebUtility.UrlEncode(error)}&returnUrl={model.ReturnUrl}")); } }
public async Task <ExternalUserResult> CreateOrAddExternalToUser(string email, ExternalLoginInfo info) { ApplicationUser?user = await userManager.FindByEmailAsync(email).ConfigureAwait(false); if (user != null) { if (await userManager.IsInRoleAsync(user, AuthorizationConstants.AdminRole).ConfigureAwait(false)) { // Don't link accounts for admin users, security issue.. logger.LogError("Attempt to link accounts for admin user: {0}, {1}", email, info.LoginProvider); throw new InvalidOperationException("Attempted to link account for admin user"); } IdentityResult result = await userManager.AddLoginAsync(user, info).ConfigureAwait(false); var externalResult = new ExternalUserResult(user, result, info, false); if (result.Succeeded) { logger.LogInformation("Added external login to account: {0}, {1}", email, info.LoginProvider); await emailSender.SendEmailTemplated(user.Email, "Account Linked", "AccountLinked", externalResult).ConfigureAwait(false); } else { LogErrors("Adding external login", result); } return(externalResult); } else { logger.LogInformation("Creating user from external login"); user = new ApplicationUser(email: email, registrationDate: DateTime.UtcNow); IdentityResult result = await userManager.CreateAsync(user).ConfigureAwait(false); if (result.Succeeded) { result = await userManager.AddLoginAsync(user, info).ConfigureAwait(false); if (!result.Succeeded) { LogErrors("Adding external login", result); } else { await emailSender.SendEmailTemplated(user.Email, "Account Creation", "UserCreated").ConfigureAwait(false); logger.LogInformation("Created user from external login"); } return(new ExternalUserResult(user, result, info, true)); } else { LogErrors("Creating user", result); return(new ExternalUserResult(result, info)); } } }