prevent多次登录 [英] Prevent multiple logins

查看:195
本文介绍了prevent多次登录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想阻止多次登录,在我的应用程序相同的用户。结果我的想法是,以更新安全印记,当用户登入并补充说,作为一个主张,然后在邮票从一个在数据库中的饼干比较每一个请求。这是我如何实现的:

I am trying to block multiple logins with the same user in my application.
My idea is to update the security stamp when user signin and add that as a Claim, then in every single request comparing the stamp from the cookie with the one in the database. This is how I've implemented that:

        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));

然后在认证配置我已经添加了

Then in authentication configuration I've added

        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?

As it shows I have tried to compare the claim from the cookie with the one in the database and reject the identity if they are not the same.
Now, each time the user signs in the security stamp gets updated but the value is different in user's cookie which I can't find out why? I am suspicious maybe it the new updated security stamp doesn't get stored in user's cookie?

推荐答案

解决方案是较为简单的比你开始实施。但这个想法是一样的:每次用户登录时,改变他们的安全标志。这将注销所有其他的登录会话。这样会教用户不分享他们的密码。

The solution is somewhat more simple than you have started implementing. But the idea is the same: every time user logs in, change their security stamp. And this will invalidate all other login sessions. Thus will teach users not to share their password.

我刚刚创建了从标准VS2013模板创建一个新MVC5应用程序,并成功地设法实现你想要做什么。

I have just created a new MVC5 application from standard VS2013 template and successfully managed to implement what you want to do.

登录方法。你需要在你创建auth饼干,更改安全图章作为Cookie设置后,你不能轻易更新值​​:

Login method. You need to change the security stamp BEFORE you create auth cookie, as after the cookie is set, you can't easily update the values:

[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, model.Password, model.RememberMe, 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); - 比你想象的simplier

This way every login will do an update on the user record with the new security stamp. Updating security stamp is only a matter of await UserManager.UpdateSecurityStampAsync(user.Id); - much simplier than you imagined.

下一步是检查在每次请求的安全标记。你已经找到了 Startup.Auth.cs ,但你又过于复杂的最佳挂钩的点。该框架已经做你需要做什么,你需要稍微调整它:

Next step is to check for security stamp on every request. You already found the best hook-in point in Startup.Auth.cs but you again overcomplicated. The framework already does what you need to do, you need to tweak it slightly:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    // other stuff
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    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不匹配数据库中的印章,用户的AUTH-cookie被抛出,要求其注销。

The time interval is set for zero - means the framework on every request will compare user's security stamp with the database. If stamp in the cookie does not match the stamp in the database, user's auth-cookie is thrown out, asking them to logout.

但是,请注意,这将承受来自用户的每个HTTP请求的额外请求你的数据库。在一个大的用户群这可能是昂贵的,你可以在一定程度增加检查间隔几分钟 - 会给你少请求您的数据库,但仍然会携带不共享登录信息的邮件

However, note that this will bear an extra request to your database on every HTTP request from a user. On a large user-base this can be expensive and you can somewhat increase the checking interval to a couple minutes - will give you less requests to your DB, but still will carry your message about not sharing the login details.

在github上

更多信息

这篇关于prevent多次登录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆