gpt4 book ai didi

asp.net-core - SAAS应用如何防止多次登录?

转载 作者:行者123 更新时间:2023-12-01 19:58:38 26 4
gpt4 key购买 nike

我需要做什么

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

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

我的想法

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

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

我虽然将登录用户 session 的信息存储在数据库中,但这也需要大量连接。所以我对 ASP.NET CORE 的经验不足以及网络资源的缺乏让我陷入了困境。困惑。

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

最佳答案

我创建了一个 github 存储库,其中对默认 .net core 2.1 模板进行了更改,仅允许单个 session 。 https://github.com/xKloc/IdentityWithSession

这是要点。

首先,覆盖默认值 UserClaimsPrincipalFactory<IdentityUser>具有自定义类的类,该类会将您的 session 添加到用户声明中。声明只是一个键/值对,将存储在用户的 cookie 中以及服务器上的 AspNetUserClaims 下。表。

将此类添加到项目中的任何位置。

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

接下来我们将创建一个授权处理程序,用于检查每个请求的 session 是否有效。

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

将这两个类添加到项目中的任何位置。

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

最后,只需在启动时注册这些新类,以便调用它们。

将此代码添加到您的 Startup类下ConfigureServices方法,正下方 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>();

关于asp.net-core - SAAS应用如何防止多次登录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52168543/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com