Identity.TwoFactorRememberMe 的问题和更新的用户 SecurityStamp

Problems with Identity.TwoFactorRememberMe and updated user SecurityStamp

使用验证器应用程序使用双因素登录后,我将 rememberClient 设置为 true,如下所示:

await _signInManager.TwoFactorAuthenticatorSignInAsync(code: request.Code,
                                                       isPersistent: request.IsPersistent,
                                                       rememberClient: request.RememberClient);

登录正常,我得到了 .AspNetCore.Identity.ApplicationIdentity.TwoFactorRememberMe cookie。如果我退出并再次登录,则不需要使用双因素。这么久就没事了

问题是当我对用户进行一些更改时,例如 phone 号码,并且更改了 SecurityStamp。更改完成后,我使用 await _signInManager.RefreshSignInAsync(user)。但是 Identity.TwoFactorRememberMe cookie 没有更新。这会导致两个问题:

  1. 下次登录时,我必须再次使用双因素身份验证。
  2. 在同一个会话中,如果我检查用户是否记得浏览器,使用 await _signInManager.IsTwoFactorClientRememberedAsync(user),将导致错误 "Failed to validate a security stamp" 并且 .AspNetCore.Identity.Application 将被删除。

我尝试在 .AspNetCore.Identity.Application cookie 的同时更新 Identity.TwoFactorRememberMe cookie,如下所示:

await base.RefreshSignInAsync(user);
await RememberTwoFactorClientAsync(user);

它有效,但它也会为那些以前没有它的人设置 Identity.TwoFactorRememberMe cookie。我无法检查它之前是否设置过,因为那时我得到了上面 (2) 中描述的错误。

接下来我要尝试的是在每个地方都做这样的事情,我会做一些改变用户 SecurityStamp 的事情:

var isTwoFactorClientRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user);

// do the changes...

await _signInManager.RefreshSignInAsync(user);
if (isTwoFactorClientRememberedAsync)
    await _signInManager.RememberTwoFactorClientAsync(user);

我是否遗漏了什么,或者这是唯一的方法吗?

我正在使用 IdentityServer4 和 SPA 应用程序,但我认为这与问题无关。

我最终在我的自定义 ApplicationSignInManager 中添加了一个方法:

public async Task<TResult> KeepSignInAsync<TResult>(ApplicationUser user, Func<Task<TResult>> func)
{
    var isTwoFactorClientRemembered = await IsTwoFactorClientRememberedAsync(user);

    var result = await func();

    await RefreshSignInAsync(user);

    if (isTwoFactorClientRemembered)
        await RememberTwoFactorClientAsync(user);

    return result;
}

当我更改将更新用户 SecurityStamp 的内容时,我会这样使用它:

var result = await _signInManager.KeepSignInAsync(user, () => _userManager.SetPhoneNumberAsync(user, phoneNumber));