.Net Core 2.2 Cookie认证问题

.Net Core 2.2 Cookie Authentication Problem

我是 .net 核心开发的新手,我的 .net 核心 Web 应用程序在通过 cookie 身份验证方案进行用户身份验证方面遇到了问题。问题是,即使创建了 cookie 并且我已正确登录,如果用户再次调用登录页面,我也无法自动重新登录。

下面是我的代码,以便更好地理解:

服务配置

services.AddAuthentication()
// Add operator authentication
.AddCookie("OPERATOR_AUTH", o =>
{
    o.LoginPath = "/login";
    o.LogoutPath = "/logout";
    o.AccessDeniedPath = "/denied";
    // Block js cookie access
    o.Cookie.HttpOnly = true;
    // Limit cookies to https connections in production environments
    o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    // Only allow the cookie on the service pages
    o.Cookie.SameSite = SameSiteMode.Strict;
});
services.AddTransient<ILoginService, LoginService>();

应用配置

app.UseCookiePolicy();
app.UseAuthentication();
app.Use(next => ctx =>
{
    var cookieOptions = new CookieOptions
    {
      HttpOnly = true
    };
    var tokens = antiforgery.GetAndStoreTokens(ctx);
    ctx.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,cookieOptions);
    return next(ctx);
}); 

登录控制器

/// <summary>
/// The operator login service
/// </summary>
private readonly ILoginService _loginService;
/// <summary>
/// The logger instance received by dependency
/// injection
/// </summary>
private readonly ILogger<LoginController> _logger;

/// <summary>
/// Renders the login view
/// </summary>
/// <returns></returns>
[Route("login")]
public async Task<IActionResult> Login()
{
  return View(new OperatorLoginModel());
}

/// <summary>
/// Renders the login denied view
/// </summary>
/// <returns></returns>
[Route("denied")]
public IActionResult Denied()
{
  return View();
}

/// <summary>
/// Performs a login
/// </summary>
/// <param name="model">The login model</param>
/// <returns>The result view</returns>
[Route("login")]
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<IActionResult> Login(OperatorLoginModel model)
{
  if (!ModelState.IsValid)
  {
    return View(model);
  }

  var op = await _loginService.IsAuthorizedOperator(model.OperatorCode, model.OperatorPassword);
  if (op != null)
  {
    return await SignInOperator(op);
  }
  return RedirectToAction("Denied", "Login");
}

/// <summary>
/// Performs a logout
/// </summary>
/// <returns>The result view redirection</returns>
[Route("logout")]
[ValidateAntiForgeryToken]
[HttpPost]
public async Task<IActionResult> Logout()
{
  await HttpContext.SignOutAsync("OPERATOR_AUTH");
  return RedirectToAction("Index", "Home");
}

/// <summary>
/// Performs the actual sign in by assigning the operator
/// identity to the http context
/// </summary>
/// <param name="op">The operator to sign in</param>
/// <returns>The result view redirection</returns>
private async Task<IActionResult> SignInOperator(Operator op)
{
  var claims = new List<Claim>
  {
    new Claim(ClaimTypes.NameIdentifier,op.Code),
    new Claim(ClaimTypes.Name, op.Description)
  };

  var authProperties = new AuthenticationProperties()
  {
    AllowRefresh = true,
    IsPersistent = true,
    ExpiresUtc = DateTimeOffset.Now.AddMinutes(30).UtcDateTime,
    IssuedUtc = DateTimeOffset.Now.UtcDateTime
  };

  var identity = new ClaimsIdentity(claims, "OPERATOR_AUTH");
  var principal = new ClaimsPrincipal(identity);

  await HttpContext.SignInAsync("OPERATOR_AUTH", principal, authProperties);
  return RedirectToAction("UserInformation", "Home");
}

/// <summary>
/// Constructor of the login controller
/// </summary>
/// <param name="logger">Logger instance</param>
/// <param name="loginService">Login service</param>   
public LoginController(ILogger<LoginController> logger, ILoginService loginService)
{
  _logger = logger;
  _loginService = loginService;
}

发生以下情况:

现在,如果我注销,cookie 会被正确删除。

如果我不登录,而是刷新页面或重新导航到 Home/Login,我将无法在 HttpContext 中接收用户信息:

也没有自动验证。

我错过了什么吗?这里有什么问题吗?

正如 kirk larkin 提到的那样,可以通过向控制器方法添加授权上下文属性以及匿名上下文属性来解决该问题。

[Route("login")]
[AllowAnonymous]
[Authorize(AuthenticationSchemes = "OPERATOR_AUTH")]
public IActionResult Login()
{
  if (HttpContext.User.Identity.IsAuthenticated)
  {
    return RedirectToAction("UserInformation", "Home");
  }
  return View(new OperatorLoginModel());
}