【问题标题】:How to extend and validate session in ASP.NET Core Identity?如何在 ASP.NET Core Identity 中扩展和验证会话?
【发布时间】:2020-03-31 18:17:05
【问题描述】:

我们希望让用户管理他们的登录会话。 到目前为止,使用 ASP.NET Core 并且没有身份扩展,这非常容易。

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.1#react-to-back-end-changes

但是我们如何使用 ASP.NET Core Identity 调用此验证呢?

我们遇到的问题:

  • 我们如何存储基于登录会话的信息,例如浏览器版本、设备类型和用户位置?我们是否扩展了任何类型或想法是什么?
  • 我们如何根据特定用户动态设置 cookie 过期时间?
  • 我们如何从后端使 Cookie 失效(如上面的链接所示)?
  • 特殊功能如何要求额外的密码提示?

感觉 ASP.NET Core Identity 的可扩展性和灵活性还不够 :(

【问题讨论】:

  • 对于#1,请查看应用程序指纹。对于其他人,您是在谈论允许用户设置到期时间吗?对于 #4 用户声明应该告诉您用户可以做什么和不能做什么。
  • 谢谢@Train,您对应用程序指纹识别是什么意思?我认为我们可以扩展存储会话的现有模型(如用户登录)并扩展它们......?关于到期时间,是的,用户可以选择到期时间 - 我们希望为特殊用户(如特殊国家的人)强制执行较低的到期时间。对于 4:我们希望在电子邮件编辑或订单提交等时要求密码提示。
  • 对于#1,试试en.wikipedia.org/wiki/Device_fingerprint。这会为您提供浏览器信息、插件、设备类型等......您可以将其添加到用户声明中。所有登录会话和用户信息都应存储在声明中。几年前我在没有身份的情况下做过类似的事情,你可能需要一个图书馆来做这件事。
  • 对于#2,您尝试过这样的事情吗? stackoverflow.com/questions/52952488/…在用户声明中设置过期时间,并从中获取值。
  • 对于#3,您将不得不向我们展示使 cookie 失效的尝试,尝试设置一个在线示例。对于#4,您可以 1. 具有额外角色的用户身份,2. 旧式提示方式。很难判断是否没有代码,我无法提供更多信息,因为这个问题很广泛,没有代码。

标签: asp.net-core asp.net-core-identity


【解决方案1】:

不幸的是,ASP.NET 身份的这个领域没有很好的文档记录,我个人认为这是一个敏感领域的风险。

在我更多地接触源代码之后,解决方案似乎是使用登录管理器的登录过程。

基本问题是,将您的自定义声明放入 cookie 的 ClaimsIdentity 并不容易。没有办法。 这个值在任何情况下都不能存储在数据库中用户的声明中,否则每个登录都会收到这些声明 - 会很糟糕。

所以我创建了自己的方法,它首先在数据库中搜索用户,然后使用 SignInManager 的现有方法。

在登录管理器创建 ClaimsIdentity 后,您可以使用自己的声明来丰富身份。 为此,我将登录会话与 Guid 保存在数据库中,并将 id 作为 cookie 中的声明。

    public async Task<SignInResult> SignInUserAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)
    {
        DateTimeOffset createdLoginOn = DateTimeOffset.UtcNow;
        DateTimeOffset validTo = createdLoginOn.AddSeconds(_userAuthOptions.ExpireTimeSeconds);

        // search for user
        var user = await _userManager.FindByNameAsync(userName);
        if (user is null) { return SignInResult.Failed; }


        // CheckPasswordSignInAsync checks if user is allowed to sign in and if user is locked
        // also it checks and counts the failed login attempts
        var attempt = await CheckPasswordSignInAsync(user, password, lockoutOnFailure);
        if (attempt.Succeeded)
        {
            // TODO: Check 2FA here

            // create a unique login entry in the backend
            string browserAgent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"];

            Guid loginId = await _eventDispatcher.Send(new AddUserLoginCommand(user.Id, user.UserName, createdLoginOn, validTo, browserAgent));

            // Write the login id in the login claim, so we identify the login context
            Claim[] customClaims = { new Claim(CustomUserClaims.UserLoginSessionId, loginId.ToString()) };

            // Signin User
            await SignInWithClaimsAsync(user, isPersistent, customClaims);

            return SignInResult.Success;
        }

        return attempt;
    }

对于每个请求,我都可以验证 ClaimsIdentity 并搜索登录 ID。

public class CookieSessionValidationHandler : CookieAuthenticationEvents
{
    public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        ClaimsPrincipal userPrincipal = context.Principal;

        if (!userPrincipal.TryGetUserSessionInfo(out int userId, out Guid sessionId))
        {
            // session format seems to be invalid
            context.RejectPrincipal();
        }
        else
        {
            IEventDispatcher eventDispatcher = context.HttpContext.RequestServices.GetRequiredService<IEventDispatcher>();

            bool succeeded = await eventDispatcher.Send(new UserLoginUpdateLoginSessionCommand(userId, sessionId));
            if (!succeeded)
            {
                // session expired or was killed
                context.RejectPrincipal();
            }
        }
    }
}

另请参阅 https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-3.1#react-to-back-end-changes

【讨论】:

    猜你喜欢
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 2017-09-03
    • 2016-09-16
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多