ExternalLogins.cshtml.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. #nullable disable
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. using bitforum.Models.User;
  10. using Microsoft.AspNetCore.Authentication;
  11. using Microsoft.AspNetCore.Identity;
  12. using Microsoft.AspNetCore.Mvc;
  13. using Microsoft.AspNetCore.Mvc.RazorPages;
  14. namespace bitforum.Areas.Identity.Pages.Account.Manage
  15. {
  16. public class ExternalLoginsModel : PageModel
  17. {
  18. private readonly UserManager<ApplicationUser> _userManager;
  19. private readonly SignInManager<ApplicationUser> _signInManager;
  20. private readonly IUserStore<ApplicationUser> _userStore;
  21. public ExternalLoginsModel(
  22. UserManager<ApplicationUser> userManager,
  23. SignInManager<ApplicationUser> signInManager,
  24. IUserStore<ApplicationUser> userStore)
  25. {
  26. _userManager = userManager;
  27. _signInManager = signInManager;
  28. _userStore = userStore;
  29. }
  30. /// <summary>
  31. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  32. /// directly from your code. This API may change or be removed in future releases.
  33. /// </summary>
  34. public IList<UserLoginInfo> CurrentLogins { get; set; }
  35. /// <summary>
  36. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  37. /// directly from your code. This API may change or be removed in future releases.
  38. /// </summary>
  39. public IList<AuthenticationScheme> OtherLogins { get; set; }
  40. /// <summary>
  41. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  42. /// directly from your code. This API may change or be removed in future releases.
  43. /// </summary>
  44. public bool ShowRemoveButton { get; set; }
  45. /// <summary>
  46. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  47. /// directly from your code. This API may change or be removed in future releases.
  48. /// </summary>
  49. [TempData]
  50. public string StatusMessage { get; set; }
  51. public async Task<IActionResult> OnGetAsync()
  52. {
  53. var user = await _userManager.GetUserAsync(User);
  54. if (user == null)
  55. {
  56. return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
  57. }
  58. CurrentLogins = await _userManager.GetLoginsAsync(user);
  59. OtherLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
  60. .Where(auth => CurrentLogins.All(ul => auth.Name != ul.LoginProvider))
  61. .ToList();
  62. string passwordHash = null;
  63. if (_userStore is IUserPasswordStore<ApplicationUser> userPasswordStore)
  64. {
  65. passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted);
  66. }
  67. ShowRemoveButton = passwordHash != null || CurrentLogins.Count > 1;
  68. return Page();
  69. }
  70. public async Task<IActionResult> OnPostRemoveLoginAsync(string loginProvider, string providerKey)
  71. {
  72. var user = await _userManager.GetUserAsync(User);
  73. if (user == null)
  74. {
  75. return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
  76. }
  77. var result = await _userManager.RemoveLoginAsync(user, loginProvider, providerKey);
  78. if (!result.Succeeded)
  79. {
  80. StatusMessage = "The external login was not removed.";
  81. return RedirectToPage();
  82. }
  83. await _signInManager.RefreshSignInAsync(user);
  84. StatusMessage = "The external login was removed.";
  85. return RedirectToPage();
  86. }
  87. public async Task<IActionResult> OnPostLinkLoginAsync(string provider)
  88. {
  89. // Clear the existing external cookie to ensure a clean login process
  90. await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
  91. // Request a redirect to the external login provider to link a login for the current user
  92. var redirectUrl = Url.Page("./ExternalLogins", pageHandler: "LinkLoginCallback");
  93. var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
  94. return new ChallengeResult(provider, properties);
  95. }
  96. public async Task<IActionResult> OnGetLinkLoginCallbackAsync()
  97. {
  98. var user = await _userManager.GetUserAsync(User);
  99. if (user == null)
  100. {
  101. return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
  102. }
  103. var userId = await _userManager.GetUserIdAsync(user);
  104. var info = await _signInManager.GetExternalLoginInfoAsync(userId);
  105. if (info == null)
  106. {
  107. throw new InvalidOperationException($"Unexpected error occurred loading external login info.");
  108. }
  109. var result = await _userManager.AddLoginAsync(user, info);
  110. if (!result.Succeeded)
  111. {
  112. StatusMessage = "The external login was not added. External logins can only be associated with one account.";
  113. return RedirectToPage();
  114. }
  115. // Clear the existing external cookie to ensure a clean login process
  116. await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
  117. StatusMessage = "The external login was added.";
  118. return RedirectToPage();
  119. }
  120. }
  121. }