ExternalLogins.cshtml.cs 5.8 KB

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