如何在ASP.NET Core Identity中扩展和验证会话?

问题描述 投票:0回答:1

我们希望为用户提供管理其登录会话的方法。到目前为止,使用ASP.NET Core进行此操作非常容易,并且没有Identity Extensions。

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身份仍然没有那么可扩展和灵活:(

asp.net-core asp.net-core-identity
1个回答
0
投票

不幸的是,ASP.NET Identity的这一领域记录得不好,我个人认为这是对此类敏感区域的风险。

在我更加关注源代码之后,解决方案似乎是使用SignIn Manager的SignIn过程。

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

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

[由登录管理器创建了ClaimsIdentity之后,您可以使用自己的声明来丰富Identity。为此,我将带有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

© www.soinside.com 2019 - 2024. All rights reserved.