You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:00:58