ASP.NET Core MVC中员工控制器创建的用户无法登录问题
问题:创建员工同步生成用户后无法登录
在ASP.NET Core MVC项目中,通过EmployeeController的Create方法创建员工时,同步生成ApplicationUser记录到数据库,但使用该用户登录时提示Invalid Login Attempt,而通过注册页面创建的用户可正常登录。
相关代码
EmployeeController的Create方法
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create([Bind("Id,EmployeeRole,Department,Name,Phone,Address,Email,JoinedDate,Salary")] Employee employee) { var defaultUser = new ApplicationUser { UserName = employee.Name, Email = employee.Email, PhoneNumber = employee.Phone, Address = employee.Address, EmployeeRole = employee.EmployeeRole, Department = employee.Department, EmailConfirmed = true, PhoneNumberConfirmed = true }; if (_userManager.Users.All(u =>u.Email != defaultUser.Email)) { var user = await _userManager.FindByEmailAsync(defaultUser.Email); if (user == null) { await _userManager.CreateAsync(defaultUser, "123Pa$$word."); } } if (ModelState.IsValid) { _context.Add(employee); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } return View(employee); }
Program.cs中的Identity依赖注入
var connectionString = builder.Configuration.GetConnectionString("LocalDatabase"); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultUI() .AddDefaultTokenProviders();
ApplicationDbContext代码
public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() { } public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<HRMS.Models.Employee> Employees { get; set; } public DbSet<HRMS.Models.Service> Services { get; set; } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.HasDefaultSchema("Identity"); builder.Entity<IdentityUser>(entity => { entity.ToTable(name: "User"); }); builder.Entity<IdentityRole>(entity => { entity.ToTable(name: "Role"); }); builder.Entity<IdentityUserRole<string>>(entity => { entity.ToTable("UserRoles"); }); builder.Entity<IdentityUserClaim<string>>(entity => { entity.ToTable("UserClaims"); }); builder.Entity<IdentityUserLogin<string>>(entity => { entity.ToTable("UserLogins"); }); builder.Entity<IdentityRoleClaim<string>>(entity => { entity.ToTable("RoleClaims"); }); builder.Entity<IdentityUserToken<string>>(entity => { entity.ToTable("UserTokens"); }); } }
注册页面代码(Registration.cs)
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); if (result.Succeeded) { _logger.LogInformation("User created a new account with password."); var userId = await _userManager.GetUserIdAsync(user); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); var callbackUrl = Url.Page( "/Account/ConfirmEmail", pageHandler: null, values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl }, protocol: Request.Scheme); await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); 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); } } // 省略后续代码 }
问题原因
- 用户名不匹配:注册页面将
UserName设为用户邮箱,但Create方法中UserName设为员工姓名。ASP.NET Core Identity默认用UserName做登录验证,若用户登录时输入邮箱,系统找不到对应UserName,导致登录失败。 - 未检查用户创建结果:Create方法调用
_userManager.CreateAsync后未验证操作是否成功,若存在密码规则不匹配等隐性错误,会导致用户记录生成但密码未正确哈希存储。 - 冗余的重复检查:先通过
_userManager.Users.All判断邮箱是否存在,再调用FindByEmailAsync,逻辑冗余且可能因异步操作导致数据不一致。
解决方案
方案1:统一用户名与邮箱(推荐)
修改Create方法中ApplicationUser的UserName赋值,与注册页面保持一致,设为员工邮箱:
var defaultUser = new ApplicationUser { UserName = employee.Email, // 改为邮箱,和注册页逻辑一致 Email = employee.Email, PhoneNumber = employee.Phone, Address = employee.Address, EmployeeRole = employee.EmployeeRole, Department = employee.Department, EmailConfirmed = true, PhoneNumberConfirmed = true }; // 简化重复检查逻辑 var existingUser = await _userManager.FindByEmailAsync(defaultUser.Email); if (existingUser == null) { var createResult = await _userManager.CreateAsync(defaultUser, "123Pa$$word."); // 检查创建结果,处理错误 if (!createResult.Succeeded) { foreach (var error in createResult.Errors) { ModelState.AddModelError(string.Empty, error.Description); } return View(employee); } }
方案2:配置Identity允许邮箱登录
若需保留UserName为员工姓名,可配置Identity支持通过邮箱登录:
在Program.cs中修改Identity配置:
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options => { options.User.RequireUniqueEmail = true; options.SignIn.RequireConfirmedAccount = false; // 根据业务需求调整 }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultUI() .AddDefaultTokenProviders(); // 配置登录验证逻辑,支持邮箱登录 builder.Services.AddScoped<SignInManager<ApplicationUser>>();
同时,修改登录逻辑,优先通过邮箱查找用户:
// 登录方法示例 var user = await _userManager.FindByEmailAsync(Input.Email); if (user == null) { user = await _userManager.FindByNameAsync(Input.Email); } if (user != null && await _userManager.CheckPasswordAsync(user, Input.Password)) { await _signInManager.SignInAsync(user, Input.RememberMe); return LocalRedirect(returnUrl); } ModelState.AddModelError(string.Empty, "Invalid Login Attempt");
额外建议
- 避免硬编码密码,可通过配置文件存储默认初始密码。
- 确保密码符合Identity默认规则(至少6位,包含大小写、数字、特殊字符)。
- 生产环境中开启邮箱验证(
RequireConfirmedEmail),提升账号安全性。
内容的提问来源于stack exchange,提问作者soe thein
相关产品推荐
相关产品推荐

