ASP.NET Core极简API登录认证流程实操疑问
核心逻辑澄清
HttpOnly Cookie的核心优势就是禁止JavaScript访问,避免XSS窃取,但浏览器会自动在同域/允许跨域凭证的请求中携带该Cookie,不需要手动在Authorization头里追加令牌——你需要调整API的认证逻辑,让它从Cookie里读取JWT,而非只认Header中的Bearer令牌。
你需要补充的关键环节
1. 修改登录端点:将JWT写入HttpOnly Cookie
当前登录端点直接返回令牌,需改为生成令牌后写入Cookie,不再返回给前端。调整后的代码示例:
app.MapPost("/login", async (LoginModel model, UserService userService, TokenService tokenService) => { var userExists = await userService.UserExistsAsync(model.Username); if (!userExists) return Results.Unauthorized(); var user = await userService.SignInUserAsync(model); if (user == null) return Results.Unauthorized(); // 建议用用户实际信息生成令牌,而非登录请求model var token = tokenService.GenerateToken(user); // 配置Cookie安全属性,这是安全保障的核心 var cookieOptions = new CookieOptions { HttpOnly = true, // 禁止JS访问,拦截XSS窃取 Secure = builder.Environment.IsProduction(), // 生产环境强制HTTPS下生效 SameSite = SameSiteMode.Strict, // 防范CSRF攻击 Expires = DateTime.UtcNow.AddHours(1), // 和令牌过期时间保持一致 Path = "/" // 确保全站请求都能携带该Cookie }; // 将令牌写入Cookie,而非返回给前端 return Results.Cookie("AuthToken", token, cookieOptions); });
2. 配置API认证中间件:从Cookie读取JWT
默认JWT Bearer中间件仅从Authorization: Bearer <token>头读取令牌,需修改事件逻辑,让它优先从Cookie提取令牌:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 保留你原有的TokenValidationParameters配置 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidateAudience = true, ValidAudience = builder.Configuration["Jwt:Audience"], ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])) }; // 新增:从Cookie获取令牌的逻辑 options.Events = new JwtBearerEvents { OnMessageReceived = context => { if (!string.IsNullOrEmpty(context.Request.Cookies["AuthToken"])) { context.Token = context.Request.Cookies["AuthToken"]; } return Task.CompletedTask; } }; });
3. 客户端Fetch请求:配置携带凭证
前端发起API请求时,必须指定凭证携带规则,否则浏览器不会自动发送HttpOnly Cookie:
- 同域场景:使用
credentials: 'same-origin' - 跨域场景:使用
credentials: 'include'(需配合API的CORS配置)
示例代码:
// 同域请求示例 fetch('/api/your-protected-endpoint', { method: 'GET', credentials: 'same-origin' }) .then(res => res.json()) .then(data => console.log(data)); // 跨域请求示例 fetch('https://your-api-domain.com/api/protected', { method: 'GET', credentials: 'include' }) .then(res => res.json()) .then(data => console.log(data));
4. 跨域场景补充:配置CORS允许凭证
如果你的Razor Pages和API不在同一域名下,必须在API端配置CORS策略,明确允许携带凭证:
builder.Services.AddCors(options => { options.AddPolicy("AllowRazorPagesClient", policy => { policy.WithOrigins("https://your-razor-pages-domain.com") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 必须开启,否则Cookie不会被跨域发送 }); }); // 确保CORS中间件在认证中间件之前执行 app.UseCors("AllowRazorPagesClient"); app.UseAuthentication(); app.UseAuthorization();
额外安全建议
- 令牌过期时间不宜过长,可同时实现刷新令牌逻辑(同样存入HttpOnly Cookie)
- 生产环境必须强制开启
Secure = true,确保Cookie仅在HTTPS链路传输 - Razor Pages默认已启用CSRF防护,跨域场景需额外验证CSRF令牌
内容的提问来源于stack exchange,提问作者Ortund
相关产品推荐
相关产品推荐

