在ASP.NET Core 6 Identity 中如何使用用户名而不是邮件来登录?

Zhi Lv - MSFT 32,446 信誉分 Microsoft 供应商
2024-03-14T07:33:18.0033333+00:00

我正在做一个使用Identity 做身份认证的 ASP.NET Core 6 项目。在默认的 Register.cshtml 页中,有一个文本框用于输入电子邮件并确认电子邮件。我修改了此页面,使用名为“UserCreatedUserName”的新字段,并将其保存在 AspNetUsers 表中的新字段中。此新字段的数据类型为长度为 6 到 10 个字符的字符串。但是,我也在收集和保存电子邮件。 在登录页面中,它需要电子邮件和密码进行身份验证。但是,就我而言,我想使用用户输入“UserCreatedUserName”,我在上面已经解释过,而不是电子邮件。当我在互联网上搜索时,所有示例都显示将电子邮件替换为用户名,而不是同时收集电子邮件和用户名,然后使用用户名和密码登录。可能我必须覆盖 signInManager.PasswordSignInAsync() 或创建一个新的 signinmanager,以便它使用 UserCreatedUserName 和密码的组合,而不是电子邮件和密码。但是,我不熟悉如何实现它。任何帮助将不胜感激。

注意: 此问题总结整理于:如何使用用户创建的用户名登录,而不是电子邮件

ASP.NET Core
ASP.NET Core
.NET Framework 中一套用于生成 Web 应用程序和 XML Web 服务的技术。
32 个问题
0 个注释 无注释
{count} 票

接受的答案
  1. XuDong Peng-MSFT 10,746 信誉分 Microsoft 供应商
    2024-03-15T01:32:48.75+00:00

    你好,

    你可以参考下面的示例:

    添加 ApplicationUser:

    public class ApplicationUser : IdentityUser
    {
        [StringLength(10, MinimumLength = 6, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.")]
        public string UserCreatedUserName { get; set; }
    }
    

    修改ApplicationDBCOntext:

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    

    接下来,搭建 Identity 的基架,并确保选择:ApplicationDbContext 用户图像

    在Identity 基架搭建完之后,您需要更改如下代码:

    Register.cshtml.cs:在InputModel 模型中添加UserCreatedUserName 属性,通过Input.UserCreatedUserName来设置UserCreatedUserName 的值。

    public class RegisterModel : PageModel
    {
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IUserStore<ApplicationUser> _userStore;
        private readonly IUserEmailStore<ApplicationUser> _emailStore;
        private readonly ILogger<RegisterModel> _logger;
        public RegisterModel(
            UserManager<ApplicationUser> userManager,
            IUserStore<ApplicationUser> userStore,
            SignInManager<ApplicationUser> signInManager,
            ILogger<RegisterModel> logger)
        {
            _userManager = userManager;
            _userStore = userStore;
            _emailStore = GetEmailStore();
            _signInManager = signInManager;
            _logger = logger;
        }
    
        [BindProperty]
        public InputModel Input { get; set; }
        public string ReturnUrl { get; set; }
        public IList<AuthenticationScheme> ExternalLogins { get; set; }
        public class InputModel
        {
            [Required]
            [StringLength(10, MinimumLength = 6, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.")]
            public string UserCreatedUserName { get; set; }
    
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email { get; set; }
    
            [Required]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
    
            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }
        }
    
        public async Task OnGetAsync(string returnUrl = null)
        {
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        }
    
        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = CreateUser();
                //set the username
                await _userStore.SetUserNameAsync(user, Input.UserCreatedUserName, CancellationToken.None);
                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
                user.UserCreatedUserName = Input.UserCreatedUserName;    //add this line....
                var result = await _userManager.CreateAsync(user, Input.Password);
                if (result.Succeeded)
                {
                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }
            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 register page in /Areas/Identity/Pages/Account/Register.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;
        }
    }
    

    Register.cshtml:添加UserCreatedUserName 文本框来输入用户名

    @page
    @model RegisterModel
    @{
        ViewData["Title"] = "Register";
    }
    
    <h1>@ViewData["Title"]</h1>
    <div class="row">
        <div class="col-md-4">
            <form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
                <h2>Create a new account.</h2>
                <hr />
                <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
                <div class="form-floating mb-3">
                    <input asp-for="Input.UserCreatedUserName" class="form-control" autocomplete="username" aria-required="true" />
                    <label asp-for="Input.UserCreatedUserName">UserName</label>
                    <span asp-validation-for="Input.UserCreatedUserName" class="text-danger"></span>
                </div>
                <div class="form-floating mb-3">
                    <input asp-for="Input.Email" class="form-control" aria-required="true" placeholder=name@example.com />
                    <label asp-for="Input.Email">Email</label>
                    <span asp-validation-for="Input.Email" class="text-danger"></span>
                </div>
                <div class="form-floating mb-3">
                    <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
                    <label asp-for="Input.Password">Password</label>
                    <span asp-validation-for="Input.Password" class="text-danger"></span>
                </div>
                <div class="form-floating mb-3">
                    <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
                    <label asp-for="Input.ConfirmPassword">Confirm Password</label>
                    <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
                </div>
                <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
            </form>
        </div>
        <div class="col-md-6 col-md-offset-2">
            <section>
                <h3>Use another service to register.</h3>
                <hr />
                @{
                    if ((Model.ExternalLogins?.Count ?? 0) == 0)
                    {
                        <div>
                            <p>
                                There are no external authentication services configured. See this <a href=https://go.microsoft.com/fwlink/?LinkID=532715>article
                                about setting up this ASP.NET application to support logging in via external services</a>.
                            </p>
                        </div>
                    }
                    else
                    {
                        <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                            <div>
                                <p>
                                    @foreach (var provider in Model.ExternalLogins!)
                                    {
                                        <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                    }
                                </p>
                            </div>
                        </form>
                    }
                }
            </section>
        </div>
    </div>
    @section Scripts {
        <partial name="_ValidationScriptsPartial" />
    }
    

    Login.cshtml.cs:在InputModel模型中添加UserCreatedUserName,使用 Input.UserCreatedUserName来验证用户。

    var result = await _signInManager.PasswordSignInAsync(Input.UserCreatedUserName, Input.Password, Input.RememberMe, lockoutOnFailure: false);)
    

    完整代码:

    public class LoginModel : PageModel
    {
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly ILogger<LoginModel> _logger;
        public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }
        [BindProperty]
        public InputModel Input { get; set; }  
        public IList<AuthenticationScheme> ExternalLogins { get; set; }     
        public string ReturnUrl { get; set; }
        [TempData]
        public string ErrorMessage { get; set; }
        public class InputModel
        {
            [Required]
            public string UserCreatedUserName { get; set; }          
            [Required]
            [DataType(DataType.Password)]
            public string Password { get; set; }
            [Display(Name = "Remember me?")]
            public bool RememberMe { get; set; }
        }
        public async Task OnGetAsync(string returnUrl = null)
        {
            if (!string.IsNullOrEmpty(ErrorMessage))
            {
                ModelState.AddModelError(string.Empty, ErrorMessage);
            }
            returnUrl ??= Url.Content("~/");
            // Clear the existing external cookie to ensure a clean login process
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            ReturnUrl = returnUrl;
        }
        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                var result = await _signInManager.PasswordSignInAsync(Input.UserCreatedUserName, Input.Password, Input.RememberMe, lockoutOnFailure: false);
                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");
                    return LocalRedirect(returnUrl);
                }
                if (result.RequiresTwoFactor)
                {
                    return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account locked out.");
                    return RedirectToPage("./Lockout");
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return Page();
                }
            }
            // If we got this far, something failed, redisplay form
            return Page();
        }
    }
    

    Login.cshtml:使用UserCreatedUserName 来输入用户名,用来登录

    @page
    @model LoginModel
    @{
        ViewData["Title"] = "Log in";
    }
    <h1>@ViewData["Title"]</h1>
    <div class="row">
        <div class="col-md-4">
            <section>
                <form id="account" method="post">
                    <h2>Use a local account to log in.</h2>
                    <hr />
                    <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
                    <div class="form-floating mb-3">
                        <input asp-for="Input.UserCreatedUserName" class="form-control" autocomplete="username" aria-required="true" placeholder=name@example.com />
                        <label asp-for="Input.UserCreatedUserName" class="form-label">UserCreatedUserName</label>
                        <span asp-validation-for="Input.UserCreatedUserName" class="text-danger"></span>
                    </div>
                    <div class="form-floating mb-3">
                        <input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
                        <label asp-for="Input.Password" class="form-label">Password</label>
                        <span asp-validation-for="Input.Password" class="text-danger"></span>
                    </div>
                    <div class="checkbox mb-3">
                        <label asp-for="Input.RememberMe" class="form-label">
                            <input class="form-check-input" asp-for="Input.RememberMe" />
                            @Html.DisplayNameFor(m => m.Input.RememberMe)
                        </label>
                    </div>
                    <div>
                        <button id="login-submit" type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
                    </div>
                    <div>
                        <p>
                            <a id="forgot-password" asp-page="./ForgotPassword">Forgot your password?</a>
                        </p>
                        <p>
                            <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
                        </p>
                        <p>
                            <a id="resend-confirmation" asp-page="./ResendEmailConfirmation">Resend email confirmation</a>
                        </p>
                    </div>
                </form>
            </section>
        </div>
        <div class="col-md-6 col-md-offset-2">
            <section>
                <h3>Use another service to log in.</h3>
                <hr />
                @{
                    if ((Model.ExternalLogins?.Count ?? 0) == 0)
                    {
                        <div>
                            <p>
                                There are no external authentication services configured. See this <a href=https://go.microsoft.com/fwlink/?LinkID=532715>article
                                about setting up this ASP.NET application to support logging in via external services</a>.
                            </p>
                        </div>
                    }
                    else
                    {
                        <form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                            <div>
                                <p>
                                    @foreach (var provider in Model.ExternalLogins!)
                                    {
                                        <button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                                    }
                                </p>
                            </div>
                        </form>
                    }
                }
            </section>
        </div>
    </div>
    @section Scripts {
        <partial name="_ValidationScriptsPartial" />
    }
    

    如果答案是正确的,请点击“接受答案”并点赞。 如果您对此答案还有其他疑问,请点击“评论”。 注意:如果您想接收相关电子邮件,请按照我们的文档中的步骤启用电子邮件通知 此线程的通知。

    0 个注释 无注释

0 个其他答案

排序依据: 非常有帮助

你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。