| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- #nullable disable
- using System;
- using System.ComponentModel.DataAnnotations;
- using System.Security.Claims;
- using System.Text;
- using System.Text.Encodings.Web;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Authorization;
- using Microsoft.Extensions.Options;
- using Microsoft.AspNetCore.Identity;
- using Microsoft.AspNetCore.Identity.UI.Services;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.AspNetCore.Mvc.RazorPages;
- using Microsoft.AspNetCore.WebUtilities;
- using Microsoft.Extensions.Logging;
- using bitforum.Models.User;
- namespace bitforum.Areas.Identity.Pages.Account
- {
- [AllowAnonymous]
- public class ExternalLoginModel : PageModel
- {
- private readonly SignInManager<ApplicationUser> _signInManager;
- private readonly UserManager<ApplicationUser> _userManager;
- private readonly IUserStore<ApplicationUser> _userStore;
- private readonly IUserEmailStore<ApplicationUser> _emailStore;
- private readonly IEmailSender _emailSender;
- private readonly ILogger<ExternalLoginModel> _logger;
- public ExternalLoginModel(
- SignInManager<ApplicationUser> signInManager,
- UserManager<ApplicationUser> userManager,
- IUserStore<ApplicationUser> userStore,
- ILogger<ExternalLoginModel> logger,
- IEmailSender emailSender)
- {
- _signInManager = signInManager;
- _userManager = userManager;
- _userStore = userStore;
- _emailStore = GetEmailStore();
- _logger = logger;
- _emailSender = emailSender;
- }
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- [BindProperty]
- public InputModel Input { get; set; }
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- public string ProviderDisplayName { get; set; }
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- public string ReturnUrl { get; set; }
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- [TempData]
- public string ErrorMessage { get; set; }
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- public class InputModel
- {
- /// <summary>
- /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
- /// directly from your code. This API may change or be removed in future releases.
- /// </summary>
- [Required]
- [EmailAddress]
- public string Email { get; set; }
- }
-
- public IActionResult OnGet() => RedirectToPage("./Login");
- public IActionResult OnPost(string provider, string returnUrl = null)
- {
- // Request a redirect to the external login provider.
- var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
- var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
- return new ChallengeResult(provider, properties);
- }
- public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
- {
- returnUrl = returnUrl ?? Url.Content("~/");
- if (remoteError != null)
- {
- ErrorMessage = $"Error from external provider: {remoteError}";
- return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
- }
- var info = await _signInManager.GetExternalLoginInfoAsync();
- if (info == null)
- {
- ErrorMessage = "Error loading external login information.";
- return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
- }
- // Sign in the user with this external login provider if the user already has a login.
- var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
- if (result.Succeeded)
- {
- _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider);
- return LocalRedirect(returnUrl);
- }
- if (result.IsLockedOut)
- {
- return RedirectToPage("./Lockout");
- }
- else
- {
- // If the user does not have an account, then ask the user to create an account.
- ReturnUrl = returnUrl;
- ProviderDisplayName = info.ProviderDisplayName;
- if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email))
- {
- Input = new InputModel
- {
- Email = info.Principal.FindFirstValue(ClaimTypes.Email)
- };
- }
- return Page();
- }
- }
- public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
- {
- returnUrl = returnUrl ?? Url.Content("~/");
- // Get the information about the user from the external login provider
- var info = await _signInManager.GetExternalLoginInfoAsync();
- if (info == null)
- {
- ErrorMessage = "Error loading external login information during confirmation.";
- return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
- }
- if (ModelState.IsValid)
- {
- var user = CreateUser();
- await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
- await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
- var result = await _userManager.CreateAsync(user);
- if (result.Succeeded)
- {
- result = await _userManager.AddLoginAsync(user, info);
- if (result.Succeeded)
- {
- _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
- var userId = await _userManager.GetUserIdAsync(user);
- var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
- code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
- var callbackUrl = Url.Page(
- "/Account/ConfirmEmail",
- pageHandler: null,
- values: new { area = "Identity", userId = userId, code = code },
- protocol: Request.Scheme);
- await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
- $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
- // If account confirmation is required, we need to show the link if we don't have a real email sender
- if (_userManager.Options.SignIn.RequireConfirmedAccount)
- {
- return RedirectToPage("./RegisterConfirmation", new { Email = Input.Email });
- }
- await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);
- return LocalRedirect(returnUrl);
- }
- }
- foreach (var error in result.Errors)
- {
- ModelState.AddModelError(string.Empty, error.Description);
- }
- }
- ProviderDisplayName = info.ProviderDisplayName;
- ReturnUrl = returnUrl;
- return Page();
- }
- private ApplicationUser CreateUser()
- {
- try
- {
- return Activator.CreateInstance<ApplicationUser>();
- }
- catch
- {
- throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " +
- $"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor, or alternatively " +
- $"override the external login page in /Areas/Identity/Pages/Account/ExternalLogin.cshtml");
- }
- }
- private IUserEmailStore<ApplicationUser> GetEmailStore()
- {
- if (!_userManager.SupportsUserEmail)
- {
- throw new NotSupportedException("The default UI requires a user store with email support.");
- }
- return (IUserEmailStore<ApplicationUser>)_userStore;
- }
- }
- }
|