Login.cshtml.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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 Application.Abstractions.Data;
  5. using Domain.Entities.Director;
  6. using Infrastructure.Persistence.Identity;
  7. using Microsoft.AspNetCore.Authentication;
  8. using Microsoft.AspNetCore.Authorization;
  9. using Microsoft.AspNetCore.Identity;
  10. using Microsoft.AspNetCore.Identity.UI.Services;
  11. using Microsoft.AspNetCore.Mvc;
  12. using Microsoft.AspNetCore.Mvc.RazorPages;
  13. using Microsoft.Extensions.Logging;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.ComponentModel.DataAnnotations;
  17. using System.Linq;
  18. using System.Threading.Tasks;
  19. namespace Admin.Areas.Identity.Pages.Account;
  20. public class LoginModel : PageModel
  21. {
  22. private readonly SignInManager<ApplicationUser> _signInManager;
  23. private readonly ILogger<LoginModel> _logger;
  24. private readonly IAppDbContext _db;
  25. public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger, IAppDbContext db)
  26. {
  27. _signInManager = signInManager;
  28. _logger = logger;
  29. _db = db;
  30. }
  31. /// <summary>
  32. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  33. /// directly from your code. This API may change or be removed in future releases.
  34. /// </summary>
  35. [BindProperty]
  36. public InputModel Input { get; set; }
  37. /// <summary>
  38. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  39. /// directly from your code. This API may change or be removed in future releases.
  40. /// </summary>
  41. public IList<AuthenticationScheme> ExternalLogins { get; set; }
  42. /// <summary>
  43. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  44. /// directly from your code. This API may change or be removed in future releases.
  45. /// </summary>
  46. public string ReturnUrl { get; set; }
  47. /// <summary>
  48. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  49. /// directly from your code. This API may change or be removed in future releases.
  50. /// </summary>
  51. [TempData]
  52. public string ErrorMessage { get; set; }
  53. /// <summary>
  54. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  55. /// directly from your code. This API may change or be removed in future releases.
  56. /// </summary>
  57. public class InputModel
  58. {
  59. /// <summary>
  60. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  61. /// directly from your code. This API may change or be removed in future releases.
  62. /// </summary>
  63. [Required]
  64. [EmailAddress]
  65. public string Email { get; set; }
  66. /// <summary>
  67. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  68. /// directly from your code. This API may change or be removed in future releases.
  69. /// </summary>
  70. [Required]
  71. [DataType(DataType.Password)]
  72. public string Password { get; set; }
  73. /// <summary>
  74. /// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
  75. /// directly from your code. This API may change or be removed in future releases.
  76. /// </summary>
  77. [Display(Name = "로그인 상태 유지")]
  78. public bool RememberMe { get; set; }
  79. }
  80. public async Task OnGetAsync(string returnUrl = null)
  81. {
  82. if (!string.IsNullOrEmpty(ErrorMessage))
  83. {
  84. ModelState.AddModelError(string.Empty, ErrorMessage);
  85. }
  86. returnUrl ??= Url.Content("~/");
  87. // Clear the existing external cookie to ensure a clean login process
  88. await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
  89. ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
  90. ReturnUrl = returnUrl;
  91. }
  92. public async Task<IActionResult> OnPostAsync(string returnUrl = null)
  93. {
  94. returnUrl ??= Url.Content("~/");
  95. ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
  96. if (ModelState.IsValid)
  97. {
  98. var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
  99. var userAgent = HttpContext.Request.Headers.UserAgent.ToString();
  100. if (userAgent?.Length > 512)
  101. {
  102. userAgent = userAgent[..512];
  103. }
  104. // This doesn't count login failures towards account lockout
  105. // To enable password failures to trigger account lockout, set lockoutOnFailure: true
  106. var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
  107. if (result.Succeeded)
  108. {
  109. await _db.AdminLoginLog.AddAsync(AdminLoginLog.Create(true, Input.Email, ipAddress: ipAddress, userAgent: userAgent));
  110. await _db.SaveChangesAsync();
  111. _logger.LogInformation("User logged in.");
  112. return LocalRedirect(returnUrl);
  113. }
  114. if (result.RequiresTwoFactor)
  115. {
  116. await _db.AdminLoginLog.AddAsync(AdminLoginLog.Create(true, Input.Email, reason: "2FA 필요", ipAddress: ipAddress, userAgent: userAgent));
  117. await _db.SaveChangesAsync();
  118. return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
  119. }
  120. if (result.IsLockedOut)
  121. {
  122. await _db.AdminLoginLog.AddAsync(AdminLoginLog.Create(false, Input.Email, reason: "계정 잠김", ipAddress: ipAddress, userAgent: userAgent));
  123. await _db.SaveChangesAsync();
  124. _logger.LogWarning("User account locked out.");
  125. return RedirectToPage("./Lockout");
  126. }
  127. else
  128. {
  129. await _db.AdminLoginLog.AddAsync(AdminLoginLog.Create(false, Input.Email, reason: "로그인 실패", ipAddress: ipAddress, userAgent: userAgent));
  130. await _db.SaveChangesAsync();
  131. ModelState.AddModelError(string.Empty, "Invalid login attempt.");
  132. return Page();
  133. }
  134. }
  135. // If we got this far, something failed, redisplay form
  136. return Page();
  137. }
  138. }