如何更改现有应用程序以使用电子邮件作为登录凭据?

问题描述 投票:0回答:1

我有一个 ASP.NET Core 6.0 应用程序以及一个 SPA 应用程序。两者都使用一个 API,并且是 OIDC IdentityProvider 的客户端。

目前,用户开始使用用户名登录。它是默认 ASP.NET 标识模型中的用户名。我想更改应用程序以使用电子邮件作为登录凭据并使用户名不唯一。

我偶然发现模型中的用户名应该是唯一的,这是不可定制的行为。有什么方法可以使用户名不唯一以及允许用户使用电子邮件登录。这个问题有什么通用的方法吗?

我没有尝试太多。我发现 ASP.NET 身份模型中的用户名是唯一的,这是我不想要的。我在后端方面没有太多经验,所以很早就问了这个问题。

c# authentication authorization openid-connect asp.net-core-6.0
1个回答
0
投票

有什么方法可以使用户名不唯一并允许 用户使用电子邮件登录。有什么共同的方法吗 问题?

是的,你是对的。在asp.net core Identity中,IdentityUser的UserName是唯一的,我们无法修改。

针对你的问题,你可以添加一个自定义属性来存储非唯一的用户名,例如DisplayName,并让这个属性非唯一。然后,要允许用户使用电子邮件登录,您应该使电子邮件具有唯一性。之后更改登录页面以使用电子邮件登录并设置用户名和显示名称。请参考以下示例。

  1. 创建一个 Asp.net Core 应用程序并使用 Scaffold Identity 添加身份页面:注册、登录页面。

    从 Register.cshtml.cs 页面,我们可以看到它将使用 SetUserNameAsync 和 SetEmailAsync 方法设置用户的 UserName 和 Email,默认情况下 email 和 UserName 相同。

     public async Task<IActionResult> OnPostAsync(string returnUrl = null)
     {
         returnUrl ??= Url.Content("~/");
         ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
         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, Input.Password);
    

    如果创建用户,结果如下:

  2. Add custom user data (DisplayName) to Identity.

    创建一个 ApplicationUser 类来添加 DisplayName:

     public class ApplicationUser:IdentityUser
     {
         public string DisplayName { get; set; }             
     }
    

    在ApplicationDbContext中添加Dbset:

     public class ApplicationDbContext : IdentityDbContext
     {
         public DbSet<ApplicationUser> ApplicationUsers { get; set; }
         public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
             : base(options)
         {
         }
     }
    

    更改 Program.cs 文件中的身份服务:

     builder.Services.AddDefaultIdentity<ApplicationUser>(options => {
         options.SignIn.RequireConfirmedAccount = true; 
         options.User.RequireUniqueEmail = true; //set email unique
     })
    

    在 _LoginPartial.cshtml 和 Identity 相关页面中,将 IdentityUser 替换为 ApplicationUser。

    之后启用迁移以更新数据库:

     Add-migration AddDisplayName
     Update-database
    

    然后,AspNetUsers表如下:

  3. 更改注册页面以使用电子邮件和显示名称注册用户

    在 Register.cshtml.cs 文件中,在 InputModel 中添加 DisplayName 属性。

    在 Register.cshtml 页面中,为 DisplayName 属性添加一个文本框。

    在Register页面的OnPostAsync方法中,可以参考下面的代码设置UserName、DisplayName和Email。

     public async Task<IActionResult> OnPostAsync(string returnUrl = null)
     {
         returnUrl ??= Url.Content("~/");
         ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
         if (ModelState.IsValid)
         {
             var user = CreateUser();
    
             user.DisplayName = Input.DisplayName;
             //generate a unique UserName.
             var uniqueusername = $"{Input.DisplayName}_{Guid.NewGuid().ToString("N")}";
             await _userStore.SetUserNameAsync(user, uniqueusername, CancellationToken.None);
    
             await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
    
             var result = await _userManager.CreateAsync(user, Input.Password);
    

    登录页面OnPostAsync方法中:

    使用UserManager.FindByEmailAsync(String)Method方法先找到用户,然后使用SignInManager.PasswordSignInAsync(TUser, String, Boolean, Boolean)方法登录。

     public async Task<IActionResult> OnPostAsync(string returnUrl = null)
     {
         returnUrl ??= Url.Content("~/");
    
         ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    
         if (ModelState.IsValid)
         {
             var user = await _userManager.FindByEmailAsync(Input.Email);
    
             if (user !=null)
             { 
                 // 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(user, Input.Password, Input.RememberMe, lockoutOnFailure: false);
                 if (result.Succeeded)
                 {
                     _logger.LogInformation("User logged in.");
                     return LocalRedirect(returnUrl);
                 }
    

    结果如下:

© www.soinside.com 2019 - 2024. All rights reserved.