30 分钟后 asp.net 核心身份中缺少其他声明

Additional Claims Missing in asp.net core Identity after 30 minutes

我正在向 Claims Principal Identity 添加声明并让用户登录。在后续请求中,添加的声明在应用程序的任何位置的 Claims Principal 中可用,但仅持续 25 分钟。我没有在 25 到 30 分钟之间进行测试。 30 分钟后,Claims Principal Identity 仍然经过身份验证 但只有来自身份数据库的声明。登录时添加的 "CookieClaim" 丢失。 Claims Principal Identity "IsAuthenticated" 仍然是 true,Nav Menu 等中的问候语仍然说 "Hi emailaddress." 如果我们在 20 分钟时提出请求也没有关系。

我希望只要用户登录,这些声明就可用。

该应用程序使用 OAuth 从多个外部提供商获取用户的访问令牌和其他信息,此信息用于整个应用程序的授权。我选择将声明中的信息放在cookie中,因为它可能会定期更改,不适合存储在Identity数据库中。

以下代码来自我用来演示的 asp.net 核心 2.2 应用程序的脚手架 LoginModel。它与我的主应用程序不完全相同,但添加了声明、类型 "CookieClaim" 并使用相同的方法登录。从 "IdentityUser user..." 开始的四行实际上是我对模板 asp.net 核心 Web 应用程序所做的唯一更改(使用本地用户帐户,在构建 "Login" 页面之后)

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            IdentityUser user = await _signInManager.UserManager.FindByEmailAsync(Input.Email);
            ClaimsPrincipal currentUser = await _signInManager.CreateUserPrincipalAsync(user);
            currentUser.Identities.ElementAt(0).AddClaim(new Claim("CookieClaim", "I am in the Cookie"));
            await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, currentUser, new AuthenticationProperties());

            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }

在此应用程序的身份数据库中,我为用户添加了一个声明,键入 "IdentityDatabaseClaim." 此图像显示了登录后声明主体的声明。这不会因任何请求而改变前 25 分钟:

30 分钟后,来自数据库的声明仍然存在,但登录时在 cookie 中发送的声明类型 "CookieClaim" 不在了,如以下屏幕截图所示:

请注意,此时 IsAuthenticated 对于 Claims Principal Identity 仍然为真,Identity 数据库中的所有声明都在那里。

我已经尝试在 Startup.cs 中的 cookie 上设置 ExpireTimeSpan 但这没有效果。我很确定这个问题不是 cookie 过期,否则用户仍然无法通过身份验证。我还尝试在身份验证属性上设置 IsPersistent、IssuedUtc 和 ExpiresUtc,主要是为了避免任何人提供这些作为此问题的答案的麻烦。没有任何区别。

我需要知道什么方法或设置导致 HttpContext(看似)忽略请求 cookie 中的数据并从身份数据库创建一个新的声明主体,以及我是否可以 a) 关闭它或 b)赶上它的工作,这样我就可以在删除声明之前保存声明,并在它尝试通过下一个授权过滤器之前再次附加它们。

该行为仅在我们使用 Application.Identity 方案登录时发生(IdentityConstants.ApplicationScheme。)使用不同的方案登录,您添加到该身份的任何声明都将持续作为饼干。所以在 Startup.cs:

中的 ConfigureServices
services.AddAuthentication()
    .AddCookie("CustomClaimsCookie")

然后在登录时,在 OnGetCallbackAsync() 方法中,

ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
AuthenticationProperties props = new AuthenticationProperties();
props.StoreTokens(info.AuthenticationTokens);
await HttpContext.SignInAsync("CustomClaimsCookie", info.Principal, props);

提出的解决方案对我不起作用,但我发现了这个 https://github.com/dotnet/aspnetcore/issues/10328#issuecomment-493451017

Every 15-20 minutes makes sense, because that's when we refresh the cookie from the back end database, and as your changes don't come from there, your additional claims won't get refreshed. So there are a couple of ways to approach this;

  1. Put the claims in your identity database so they come out in the ApplicationUser
  2. Use claims transformation

第二种我试过了。它有效,但每次都会进入数据库。需要找到解决方案 - 如何在登录后更新 cookie。

然后我尝试了第一个解决方案 - 只需将“MyClaim”存储在 AspNetUserClaims 身份中 table。我们可以使用 UserManager[TUser] 管理声明。所以,看起来它有效。