Asp.NET Core 6中基于简单用户名密码校验实现用户身份认证
基于配置文件的ASP.NET Core表单身份认证实现示例
已提供的LoginViewModel
public class LoginViewModel { #region Properties /// <summary> /// Gets or sets to username address. /// </summary> [Required] [Display(Name = "Username")] public string Username { get; set; } /// <summary> /// Gets or sets to password address. /// </summary> [Required] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } #endregion }
1. 配置appsettings.json存储用户信息
在配置文件中添加允许登录的账号密码(生产环境建议存储密码哈希值,不要明文):
"AllowedUsers": [ { "Username": "admin", "Password": "Admin@123" }, { "Username": "viewer", "Password": "Viewer@123" } ]
2. 自定义用户存储服务(适配Identity框架)
因为不需要数据库,我们需要实现Identity所需的用户存储接口,读取配置文件中的用户数据:
public class ConfigUserStore : IUserStore<IdentityUser>, IUserPasswordStore<IdentityUser> { private readonly List<IdentityUser> _users; public ConfigUserStore(IConfiguration configuration) { _users = configuration.GetSection("AllowedUsers") .Get<List<IdentityUser>>() ?? new List<IdentityUser>(); // 示例:如果配置中是明文密码,这里模拟哈希存储(生产环境请提前生成哈希) var passwordHasher = new PasswordHasher<IdentityUser>(); foreach (var user in _users) { user.PasswordHash = passwordHasher.HashPassword(user, user.Password); user.NormalizedUserName = user.UserName?.ToUpper(); } } // 实现登录所需的核心方法:根据用户名查找用户 public Task<IdentityUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken) { var user = _users.FirstOrDefault(u => u.NormalizedUserName == normalizedUserName); return Task.FromResult(user); } // 获取用户密码哈希 public Task<string> GetPasswordHashAsync(IdentityUser user, CancellationToken cancellationToken) { return Task.FromResult(user.PasswordHash); } public Task<bool> HasPasswordAsync(IdentityUser user, CancellationToken cancellationToken) { return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash)); } // 其他未用到的接口方法直接返回默认实现 public Task<IdentityResult> CreateAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(IdentityResult.Failed()); public Task<IdentityResult> DeleteAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(IdentityResult.Failed()); public Task<IdentityUser> FindByIdAsync(string userId, CancellationToken cancellationToken) => Task.FromResult<IdentityUser>(null); public Task<string> GetNormalizedUserNameAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.NormalizedUserName); public Task<string> GetUserIdAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.Id); public Task<string> GetUserNameAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(user.UserName); public Task SetNormalizedUserNameAsync(IdentityUser user, string normalizedName, CancellationToken cancellationToken) { user.NormalizedUserName = normalizedName; return Task.CompletedTask; } public Task SetUserNameAsync(IdentityUser user, string userName, CancellationToken cancellationToken) { user.UserName = userName; return Task.CompletedTask; } public Task<IdentityResult> UpdateAsync(IdentityUser user, CancellationToken cancellationToken) => Task.FromResult(IdentityResult.Failed()); public Task SetPasswordHashAsync(IdentityUser user, string passwordHash, CancellationToken cancellationToken) { user.PasswordHash = passwordHash; return Task.CompletedTask; } public void Dispose() { } }
3. 配置Program.cs中的服务依赖
注册Identity和Cookie认证服务,关联自定义用户存储:
var builder = WebApplication.CreateBuilder(args); // 添加控制器与视图支持 builder.Services.AddControllersWithViews(); // 配置Identity核心服务 builder.Services.AddIdentityCore<IdentityUser>(options => { // 可根据需求配置密码规则 options.Password.RequireDigit = true; options.Password.RequireLowercase = true; options.Password.RequireUppercase = true; }) .AddUserStore<ConfigUserStore>() // 使用自定义配置用户存储 .AddSignInManager(); // 注册SignInManager // 配置Cookie认证 builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/Login"; // 未认证跳转登录页 options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie有效期 options.SlidingExpiration = true; // 滑动过期 }); var app = builder.Build(); // 中间件配置 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 启用认证与授权中间件(顺序不能错) app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
4. 实现登录控制器(AccountController.cs)
注入SignInManager,完成登录校验与身份签发:
public class AccountController : Controller { private readonly SignInManager<IdentityUser> _signInManager; public AccountController(SignInManager<IdentityUser> signInManager) { _signInManager = signInManager; } [HttpGet] public IActionResult Login() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Login(LoginViewModel model) { if (!ModelState.IsValid) { return View(model); } // 使用SignInManager自动校验用户名密码 var result = await _signInManager.PasswordSignInAsync( model.Username, model.Password, isPersistent: false, lockoutOnFailure: false); if (result.Succeeded) { return RedirectToAction("Index", "Home"); } ModelState.AddModelError(string.Empty, "用户名或密码错误"); return View(model); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Logout() { await _signInManager.SignOutAsync(); return RedirectToAction("Login"); } }
5. 登录视图(Login.cshtml)
创建对应表单页面:
@model LoginViewModel <div class="container mt-5"> <div class="row justify-content-center"> <div class="col-md-4"> <form asp-action="Login" method="post"> <div asp-validation-summary="ModelOnly" class="text-danger mb-3"></div> <div class="mb-3"> <label asp-for="Username" class="form-label"></label> <input asp-for="Username" class="form-control" /> <span asp-validation-for="Username" class="text-danger"></span> </div> <div class="mb-3"> <label asp-for="Password" class="form-label"></label> <input asp-for="Password" class="form-control" /> <span asp-validation-for="Password" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary w-100">登录</button> </form> </div> </div> </div>
关键注意事项
- 生产环境安全:绝对禁止明文存储密码,必须使用
PasswordHasher<T>生成哈希值后存入配置文件,登录时通过SignInManager自动校验哈希。 - 如果需要扩展Identity功能(如角色权限),需补充实现对应的存储接口。
内容的提问来源于stack exchange,提问作者advapi
相关产品推荐
相关产品推荐

