ASP.NET MVC 操作过滤器中的身份验证状态

Authentication state in ASP.NET MVC ActionFilters

我有一个名称为 Log 的 ActionFilter,它会在用户登录网站时记录用户 ip 和其他详细信息,因此为了完成这项工作,我编写了以下代码:

public class Log : ActionFilterAttribute
{
    public IAppUserManager UserManager { get; set; }
    
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var status = filterContext.Controller.TempData.Any(pair => pair.Key == "status" && (int)pair.Value == 200);

        if (filterContext.HttpContext.User != null && filterContext.HttpContext.User.Identity.IsAuthenticated && status)
        {
            var logIp = new AddIpAddressDto()
            {
                Browser = filterContext.HttpContext.Request.GetBrowser(),
                Ip = filterContext.HttpContext.Request.GetIp(),
                Os = filterContext.HttpContext.Request.UserAgent.GetOs(),
                UrlReferrer = filterContext.HttpContext.Request.UrlReferrer?.ToString(),
                UserId = Guid.Parse(filterContext.HttpContext.User.Identity.GetUserId()),
                UserName = filterContext.HttpContext.User.Identity.GetUserName(),
            };
            UserManager.Log(logIp);
        }
        base.OnResultExecuted(filterContext);
    }
}

此代码在 filterContext.HttpContext.User.Identity.IsAuthenticatedtrue 时有效。

登录操作上的 Log 过滤器声明:

[AllowAnonymous]
[Route("sign-in", Name = "signInRoute")]
[HttpPost, ValidateAntiForgeryToken]
[Log]
public virtual async Task<ActionResult> Login(LoginDto login, string returnTo)
{
     var signInStatus = await _signInManager
         .PasswordSignInAsync(user.UserName, login.Password, login.RememberMe, true)
            .ConfigureAwait(false);

     switch (signInStatus) // is Success
     {
         case SignInStatus.Success:
              TempData["status"] = 200;
              return RedirectToLocal(returnTo);
         case SignInStatus.LockedOut:
                // todo return time of louckout
              break;
         case SignInStatus.RequiresVerification:
              return RedirectToAction("ConfirmEmail");
         case SignInStatus.Failure:
              return View(CleanPassWordInLogin(login));
            default:
                throw new ArgumentOutOfRangeException();
     }
}

登录操作工作正常并且 signInStatus 成功 但在执行操作后 IsAuthenticatedfalse

为了解决这个问题,我尝试了以下项目:

如何解决这个问题?

执行SignInManager.PasswordSignInAsync后,将创建包含用户信息的身份验证cookie。因此 User.Identity 信息将由身份验证 cookie 中的声明填充,这些声明尚未解析(此 cookie 将在对服务器的第二个请求中解析,而不是在同一个登录请求中解析)。这就是为什么不能在 PasswordSignInAsync 之后使用 User.Identity 的原因。在这一点上,您只有一个选项来查找 userId:

 string userId = UserManager.FindByName(model.Email)?.Id;