You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core极简API登录认证流程实操疑问

解决方案:ASP.NET Core极简API + Razor Pages的JWT HttpOnly Cookie认证流程

核心逻辑澄清

HttpOnly Cookie的核心优势就是禁止JavaScript访问,避免XSS窃取,但浏览器会自动在同域/允许跨域凭证的请求中携带该Cookie,不需要手动在Authorization头里追加令牌——你需要调整API的认证逻辑,让它从Cookie里读取JWT,而非只认Header中的Bearer令牌。

你需要补充的关键环节

当前登录端点直接返回令牌,需改为生成令牌后写入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:31:19