如何防止SAAS应用程序中的多次登录? [英] How to prevent multiple login in SAAS application?

查看:99
本文介绍了如何防止SAAS应用程序中的多次登录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要做什么

我正在使用ASP.NET CORE开发应用程序,实际上我在使用Identity实现时遇到了问题.

I'm developing an application using ASP.NET CORE and I actually encountered a problem using the Identity implementation.

事实上,在正式文档中没有关于多会话的参考,这很糟糕,因为我开发了SaaS应用程序;特别是用户订阅了付费计划以访问特定功能集,并且他可以将其凭据提供给其他用户,以便他们可以免费使用,这是一个非常糟糕的情况,我会浪费很多金钱和时间.

In the official doc infact there is no reference about the multiple session, and this is bad because I developed a SaaS application; in particular a user subscribe a paid plan to access to a specific set of features and him can give his credentials to other users so they can access for free, this is a really bad scenario and I'll lose a lot of money and time.

我该怎么办

在网上搜索了很多之后,我发现了许多针对较旧版本的ASP.NET CORE的解决方案,因此我无法进行测试,但是我知道通常此问题的解决方案与存储用户有关数据库内部的时间戳(这是登录时生成的GUID),因此每次用户访问受限页面并且有更多会话(具有不同的用户时间戳)时,旧会话都会关闭.

After searching a lot on the web I found many solutions for the older version of ASP.NET CORE, so I'm not able to test, but I understood that the usually the solution for this problem is related to store the user time stamp (which is a GUID generated on the login) inside the database, so each time the user access to a restricted page and there are more session (with different user timestamp) the old session will closed.

我不喜欢这种解决方案,因为用户可以轻松复制浏览器的cookie并将其共享给其他用户.

I don't like this solution because an user can easily copy the cookie of the browser and share it will other users.

我虽然将登录的用户会话的信息存储在数据库中,但这也需要大量的连接.因此,我对ASP.NET CORE的经验不足以及网络资源的匮乏使我陷入了困境.混乱.

I though to store the information of the logged in user session inside the database, but this will require a lot of connection too.. So my inexperience with ASP.NET CORE and the lack of resource on the web have sent me in confusion.

有人可以分享一个通用的想法来实施一个安全的解决方案,以防止多用户登录吗?

Someone could share a generic idea to implement a secure solution for prevent multiple user login?

推荐答案

我创建了一个github存储库,其中包含仅允许单个会话所需的默认.net core 2.1模板的更改. https://github.com/xKloc/IdentityWithSession

I've created a github repo with the changes to the default .net core 2.1 template needed to only allow single sessions. https://github.com/xKloc/IdentityWithSession

这是要点.

首先,使用自定义类覆盖默认的UserClaimsPrincipalFactory<IdentityUser>类,该类会将您的会话添加到用户声明中.声明只是一个键/值对,将存储在用户的Cookie中,也存储在AspNetUserClaims表下的服务器上.

First, override the default UserClaimsPrincipalFactory<IdentityUser> class with a custom one that will add your session to the user claims. Claims are just a key/value pair that will be stored in the user's cookie and also on the server under the AspNetUserClaims table.

将此类添加到项目中的任何地方.

Add this class anywhere in your project.

public class ApplicationClaimsPrincipalFactory : UserClaimsPrincipalFactory<IdentityUser>
{
    private readonly UserManager<IdentityUser> _userManager;

    public ApplicationClaimsPrincipalFactory(UserManager<IdentityUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
    {
        _userManager = userManager;
    }

    public async override Task<ClaimsPrincipal> CreateAsync(IdentityUser user)
    {
        // find old sessions and remove
        var claims = await _userManager.GetClaimsAsync(user);

        var session = claims.Where(e => e.Type == "session");

        await _userManager.RemoveClaimsAsync(user, session);

        // add new session claim
        await _userManager.AddClaimAsync(user, new Claim("session", Guid.NewGuid().ToString()));

        // create principal
        var principal = await base.CreateAsync(user);

        return principal;
    }
}

接下来,我们将创建一个授权处理程序,该处理程序将检查每个请求的会话是否有效.

Next we will create an authorization handler that will check that the session is valid on every request.

处理程序会将用户cookie中的会话声明与存储在数据库中的会话声明进行匹配.如果它们匹配,则授权用户继续.如果不匹配,则用户将收到拒绝访问"消息.

The handler will match the session claim from the user's cookie to the session claim stored in the database. If they match, the user is authorized to continue. If they don't match, the user will get a Access Denied message.

在项目的任何位置添加这两个类.

Add these two classes anywhere in your project.

public class ValidSessionRequirement : IAuthorizationRequirement
{

}

public class ValidSessionHandler : AuthorizationHandler<ValidSessionRequirement>
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;

    public ValidSessionHandler(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
    {
        _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
        _signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager));
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidSessionRequirement requirement)
    {
        // if the user isn't authenticated then no need to check session
        if (!context.User.Identity.IsAuthenticated)
            return;

        // get the user and session claim
        var user = await _userManager.GetUserAsync(context.User);

        var claims = await _userManager.GetClaimsAsync(user);

        var serverSession = claims.First(e => e.Type == "session");

        var clientSession = context.User.FindFirst("session");

        // if the client session matches the server session then the user is authorized
        if (serverSession?.Value == clientSession?.Value)
        {
            context.Succeed(requirement);
        }
        return;
    }
}

最后,只需在启动时注册这些新类,即可对其进行调用.

Finally, just register these new classes in start up so they get called.

将此代码添加到ConfigureServices方法正下方services.AddDefaultIdentity<IdentityUser>() .AddEntityFrameworkStores<ApplicationDbContext>();

Add this code to your Startup class under the ConfigureServices method, right below services.AddDefaultIdentity<IdentityUser>() .AddEntityFrameworkStores<ApplicationDbContext>();

        // build default authorization policy
        var defaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddRequirements(new ValidSessionRequirement())
            .Build();

        // add authorization to the pipe
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = defaultPolicy;
        });

        // register new claims factory
        services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, ApplicationClaimsPrincipalFactory>();

        // register valid session handler
        services.AddTransient<IAuthorizationHandler, ValidSessionHandler>();

这篇关于如何防止SAAS应用程序中的多次登录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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