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

如何在ASP.NET MVC和Entity Framework中默认锁定账户15分钟及解锁?

ASP.NET MVC + Entity Framework 实现账户15分钟默认锁定与解锁方案

一、更新用户实体模型

首先需要在用户表中添加用于跟踪登录失败和锁定状态的字段,通过Entity Framework实体类实现:

public class ApplicationUser
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string PasswordHash { get; set; }
    
    // 新增锁定相关字段
    public int FailedLoginAttempts { get; set; } = 0;
    public DateTime? LockoutEndDateUtc { get; set; }
    public bool IsLockedOut { get; set; } = false;
}

执行EF迁移更新数据库,确保这些字段被添加到用户表中。

二、登录时的锁定逻辑

在登录控制器的登录方法中,加入锁定判断和失败次数累加逻辑,示例如下:

[HttpPost]
public ActionResult Login(LoginViewModel model)
{
    if (!ModelState.IsValid)
        return View(model);

    using (var db = new ApplicationDbContext())
    {
        var user = db.Users.FirstOrDefault(u => u.Username == model.Username);
        if (user == null)
        {
            ModelState.AddModelError("", "用户名或密码错误");
            return View(model);
        }

        // 先检查是否可自动解锁
        AutoUnlockUser(user);

        // 检查账户是否仍处于锁定状态
        if (user.IsLockedOut && user.LockoutEndDateUtc.HasValue && user.LockoutEndDateUtc.Value > DateTime.UtcNow)
        {
            var remainingMinutes = (user.LockoutEndDateUtc.Value - DateTime.UtcNow).TotalMinutes;
            ModelState.AddModelError("", $"账户已锁定,请等待 {Math.Ceiling(remainingMinutes)} 分钟后重试");
            return View(model);
        }

        // 验证密码(实际项目建议用成熟哈希验证逻辑)
        if (!VerifyPassword(model.Password, user.PasswordHash))
        {
            user.FailedLoginAttempts++;
            const int maxFailedAttempts = 5; // 可配置到Web.config
            if (user.FailedLoginAttempts >= maxFailedAttempts)
            {
                user.IsLockedOut = true;
                user.LockoutEndDateUtc = DateTime.UtcNow.AddMinutes(15); // 默认锁定15分钟
            }
            db.SaveChanges();
            ModelState.AddModelError("", "用户名或密码错误");
            return View(model);
        }

        // 登录成功,重置锁定状态
        user.FailedLoginAttempts = 0;
        user.IsLockedOut = false;
        user.LockoutEndDateUtc = null;
        db.SaveChanges();

        // 后续登录成功逻辑(如写入Session、跳转首页)
        Session["UserId"] = user.Id;
        return RedirectToAction("Index", "Home");
    }
}

// 密码哈希验证示例(推荐用BCrypt等算法)
private bool VerifyPassword(string inputPassword, string storedHash)
{
    return BCrypt.Net.BCrypt.Verify(inputPassword, storedHash);
}

三、账户解锁逻辑

1. 自动解锁

封装为辅助方法,在登录或权限验证时自动检查并解锁到期账户:

private void AutoUnlockUser(ApplicationUser user)
{
    if (user.IsLockedOut && user.LockoutEndDateUtc.HasValue && user.LockoutEndDateUtc.Value <= DateTime.UtcNow)
    {
        user.IsLockedOut = false;
        user.LockoutEndDateUtc = null;
        user.FailedLoginAttempts = 0;
        using (var db = new ApplicationDbContext())
        {
            db.Entry(user).State = EntityState.Modified;
            db.SaveChanges();
        }
    }
}

2. 手动解锁(管理员操作)

在后台管理界面添加手动解锁功能,允许管理员直接解除账户锁定:

[Authorize(Roles = "Admin")]
public ActionResult UnlockUser(int userId)
{
    using (var db = new ApplicationDbContext())
    {
        var user = db.Users.Find(userId);
        if (user == null)
            return HttpNotFound();

        user.IsLockedOut = false;
        user.LockoutEndDateUtc = null;
        user.FailedLoginAttempts = 0;
        db.SaveChanges();

        return RedirectToAction("UserList");
    }
}

注意事项

  • 使用DateTime.UtcNow处理时间,避免时区差异导致锁定时间不准确;
  • 失败尝试阈值可配置到Web.config,方便后续调整;
  • 生产环境需添加异常捕获,确保数据库操作稳定性;
  • 密码验证务必使用不可逆哈希算法,禁止明文存储密码。

内容的提问来源于stack exchange,提问作者Kalyan Venkateswarlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:03:24