ASP.NET前端用户无法通过[Authorize]验证:手动存JWT到Cookie无效
调用「Login」API从后端获取JWT Token后,手动将其存储到Cookie中,但访问带有[Authorize]特性的Razor页面控制器Action时,始终提示用户未认证。
想知道是否必须调用httpContext.SignInAsync()?见过一些应用未调用该方法仍能完成用户认证,请问我遗漏了什么?
相关配置代码
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/auth"; options.AccessDeniedPath = "/auth/accessdenied"; options.Cookie.IsEssential = true; options.SlidingExpiration = true; double expiresIn = 3600; options.ExpireTimeSpan = TimeSpan.FromSeconds(expiresIn); options.Cookie.Name = SConstants.JWT_COOKIE_NAME; options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict; }); // middleware app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
存储Token的代码
HttpContext.Response .Cookies .Append(SConstants.JWT_COOKIE_NAME, access_token, new CookieOptions { HttpOnly = true, Secure = true });
核心矛盾:认证方案与存储方式不匹配
你当前配置的是Cookie认证方案,但手动存储原始JWT到Cookie的逻辑和该方案不兼容。Cookie认证依赖的是ASP.NET Core生成的加密身份Cookie(内含用户声明等信息),而非你直接存入的原始JWT,所以中间件无法识别这个Cookie的身份信息。是否必须调用
SignInAsync()?
针对你当前的Cookie认证配置,必须调用。这个方法会按照Cookie认证的规则生成加密的身份Cookie,让ASP.NET Core的认证中间件能正确解析用户身份。为什么有些应用不用
SignInAsync()也能认证?
这类应用大多配置的是JWT Bearer认证方案:要么把JWT放在Authorization: Bearer <token>请求头中,要么通过自定义逻辑从Cookie读取JWT,同时后端配置了AddJwtBearer()来直接验证Token,这种场景不需要调用SignInAsync()。两种可行修正方案
方案1:遵循Cookie认证的标准流程
在Login API获取用户信息后,调用SignInAsync()生成合规的认证Cookie,替代手动存储JWT的操作:// 构造用户身份声明 var claims = new List<Claim> { new Claim(ClaimTypes.Name, "用户名"), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1), IsPersistent = false, AllowRefresh = true }; await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);执行后ASP.NET Core会自动生成符合要求的认证Cookie,后续请求时中间件能正确识别用户身份。
方案2:切换为JWT Bearer认证(适合依赖JWT的场景)
- 修改服务配置,添加JWT Bearer认证并配置从Cookie读取Token:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "你的Issuer", ValidAudience = "你的Audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的密钥")) }; // 自定义从Cookie读取JWT的逻辑 options.TokenRetriever = request => request.Cookies[SConstants.JWT_COOKIE_NAME]; });- 保留你手动存储JWT到Cookie的代码,此时认证中间件会直接从Cookie读取并验证JWT,无需调用
SignInAsync()。
当前代码的遗漏点
你配置了Cookie认证,但没有生成该方案要求的加密身份Cookie,而是存入了原始JWT,导致Cookie认证中间件无法解析用户身份,最终判定为未认证。
内容的提问来源于stack exchange,提问作者Bernardo Sousa

