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

ApplicationSignInManager是否保留成功登录列表?并发登录限制功能咨询

关于ApplicationSignInManager实现登录限制的问题

Hey there! 先直接给你答案:ApplicationSignInManager本身并没有内置「禁止同一用户多端登录」和「限制并发登录人数」的功能——它的核心职责只是处理单次登录请求的身份验证(比如密码校验),以及签发/管理用户的本地身份凭证(比如登录Cookie),不会跟踪全局的登录用户会话状态。所以你需要自己维护登录用户集合来实现这两个需求,下面给你具体的实现思路和代码参考:

一、禁止同一用户同时登录

核心思路

每次用户登录成功时,记录该用户的唯一标识(比如UserId)和当前会话的唯一ID;后续用户发起请求时,验证当前会话ID是否与记录的一致,不一致则强制登出旧会话或拒绝新登录。

结合你的代码实现

在Login方法的SignInStatus.Success分支中添加会话跟踪逻辑:

case SignInStatus.Success:
    // 获取当前登录用户的ID
    var user = await UserManager.FindByNameAsync(model.UserName);
    var userId = user.Id;
    // 生成唯一的会话ID
    var currentSessionId = Guid.NewGuid().ToString();
    var cache = MemoryCache.Default;

    // 移除该用户之前的登录记录(踢掉旧会话)
    var oldSessionId = cache.Get(userId) as string;
    if (!string.IsNullOrEmpty(oldSessionId))
    {
        // 可选:记录旧会话被踢的日志
        cache.Remove(oldSessionId);
    }
    // 缓存用户ID与当前会话ID的映射,过期时间和登录Cookie保持一致
    cache.Set(userId, currentSessionId, DateTimeOffset.Now.AddMinutes(30));
    cache.Set(currentSessionId, userId, DateTimeOffset.Now.AddMinutes(30));

    // 将会话ID写入Cookie,供后续请求验证使用
    Response.Cookies.Add(new HttpCookie("LoginSessionId", currentSessionId) { Expires = DateTime.Now.AddMinutes(30) });

    return RedirectToLocal(returnUrl);

后续请求验证示例(自定义授权属性)

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!base.AuthorizeCore(httpContext)) return false;

        var userId = httpContext.User.Identity.GetUserId();
        var cache = MemoryCache.Default;
        var validSessionId = cache.Get(userId) as string;
        var currentSessionId = httpContext.Request.Cookies["LoginSessionId"]?.Value;

        if (string.IsNullOrEmpty(currentSessionId) || currentSessionId != validSessionId)
        {
            // 会话无效,强制登出
            httpContext.GetOwinContext().Authentication.SignOut();
            return false;
        }
        return true;
    }
}

二、限制并发登录用户数不超过10人

核心思路

维护一个全局的已登录用户集合(注意区分是按「唯一用户数」还是「会话数」统计),登录前检查集合大小,超过限制则拒绝登录;登录成功后加入集合,登出或会话超时后移除。

结合你的代码实现

在Login方法的SignInStatus.Success分支中添加并发限制逻辑:

case SignInStatus.Success:
    var user = await UserManager.FindByNameAsync(model.UserName);
    var userId = user.Id;
    var cache = MemoryCache.Default;

    // 检查并发用户数(按唯一用户统计,若按会话则用sessionId)
    var loggedInUsers = cache.Get("LoggedInUsers") as HashSet<string> ?? new HashSet<string>();
    if (loggedInUsers.Count >= 10)
    {
        // 超过限制,拒绝登录并登出当前用户
        ModelState.AddModelError("", "当前在线用户过多,请稍后再试。");
        await SignInManager.SignOutAsync();
        return View(model);
    }

    // 添加当前用户到已登录集合
    loggedInUsers.Add(userId);
    cache.Set("LoggedInUsers", loggedInUsers, DateTimeOffset.Now.AddMinutes(30));

    // (加上前面同一用户多登的逻辑)

    return RedirectToLocal(returnUrl);

关键注意事项

  • 缓存选型:如果是单服务器部署,用MemoryCache即可;如果是多服务器集群,必须用分布式缓存(比如Redis、SQL Server缓存),否则不同服务器的登录状态不共享。
  • 会话清理:用户主动登出时,要从缓存中移除对应的用户/会话记录;同时给缓存设置合理的过期时间(和登录Cookie过期时间一致),避免残留无效记录。
  • 严谨性优化:如果需要更可靠的控制,可以结合JWT令牌(在令牌中嵌入会话ID),或者使用ASP.NET Session来跟踪会话状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:58:27