加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 防止多个登录

发布时间:2020-12-15 23:25:04 所属栏目:asp.Net 来源:网络整理
导读:我试图在我的应用程序中阻止同一用户的多个登录.我的想法是在用户登录时更新安全邮票,并将其添加为声明,然后在每个请求中将Cookie中的邮戳与数据库中的邮戳进行比较.这是我如何实现的: public virtual async TaskActionResult Login([Bind(Include = "Email
我试图在我的应用程序中阻止同一用户的多个登录.我的想法是在用户登录时更新安全邮票,并将其添加为声明,然后在每个请求中将Cookie中的邮戳与数据库中的邮戳进行比较.这是我如何实现的:
public virtual async Task<ActionResult> Login([Bind(Include = "Email,Password,RememberMe")] LoginViewModel model,string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        SignInStatus result =
            await SignInManager.PasswordSignInAsync(model.Email,model.Password,model.RememberMe,false);
        switch (result)
        {
            case SignInStatus.Success:
                var user = UserManager.FindByEmail(model.Email);
                var id = user.Id;
                UserManager.UpdateSecurityStamp(user.Id);
                var securityStamp = UserManager.FindByEmail(model.Email).SecurityStamp;
                UserManager.AddClaim(id,new Claim("SecurityStamp",securityStamp));

然后在我添加的身份验证配置

app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,LoginPath = new PathString("/Account/Login"),Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = ctx =>
                {
                    var ret = Task.Run(() =>
                    {
                        Claim claim = ctx.Identity.FindFirst("SecurityStamp");
                        if (claim != null)
                        {
                            var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
                            var user = userManager.FindById(ctx.Identity.GetUserId());

                            // invalidate session,if SecurityStamp has changed
                            if (user != null && user.SecurityStamp != null && user.SecurityStamp != claim.Value)
                            {
                                ctx.RejectIdentity();
                            }
                        }
                    });
                    return ret;
                }
            }

        });

如图所示,我尝试将Cookie的声明与数据库中的声明进行比较,如果不一致则拒绝该身份.
现在,每次用户登录的安全邮票都被更新,但是用户的cookie的值不同,我找不到为什么?我可能怀疑新的更新的安全邮票不会存储在用户的cookie中?

解决方法

该解决方案比您开始实施的更简单.但是想法是一样的:每次用户登录时,都要更改其安全标记.这将使所有其他登录会话无效.因此将教会用户不要分享他们的密码.

我刚刚从标准的VS2013模板创建了一个新的MVC5应用程序,并成功管理了您想要执行的操作.

登录方式.在创建验证cookie之前,您需要更改安全密码,因为cookie设置完成后,您无法轻松更新值:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model,string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }


    // check if username/password pair match.
    var loggedinUser = await UserManager.FindAsync(model.Email,model.Password);
    if (loggedinUser != null)
    {
        // change the security stamp only on correct username/password
        await UserManager.UpdateSecurityStampAsync(loggedinUser.Id);
    }

     // do sign-in
    var result = await SignInManager.PasswordSignInAsync(model.Email,shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode",new { ReturnUrl = returnUrl,RememberMe = model.RememberMe });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("","Invalid login attempt.");
            return View(model);
    }
}

这样一来,每个登录将使用新的安全印记对用户记录进行更新.更新安全邮票只是等待UserManager.UpdateSecurityStampAsync(user.Id)的问题; – 比你想象的要简单得多

下一步是在每个请求上检查安全印章.您已经在Startup.Auth.cs中找到了最佳的连接点,但是您再次过于复杂.框架已经做了你需要做的,你需要稍微调整一下:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    // other stuff
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager,ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(0),// <-- Note the timer is set for zero
            regenerateIdentity: (manager,user) => user.GenerateUserIdentityAsync(manager))
    }
});

时间间隔设置为零 – 表示每个请求上的框架将用户的安全印记与数据库进行比较.如果cookie中的邮票与数据库中的邮戳不匹配,则会抛出用户的验证cookie,要求他们注销.

但是,请注意,这将对用户的每个HTTP请求都向您的数据库提出额外的请求.在一个大的用户群上,这可能是昂贵的,您可以将检查间隔稍微增加到几分钟 – 这样可以减少对数据库的请求,但是仍然会传递关于不共享登录详细信息的消息.

Full source in github

More information in a blog-post

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读