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

ASP.NET Core MVC中JWT身份验证遇401未授权错误的问题

ASP.NET Core MVC JWT 401未授权问题解决方案

问题本质

默认JwtBearer中间件仅从Authorization: Bearer <token>请求头提取令牌,但你将JWT存储在HttpOnly Cookie中,导致中间件无法自动获取令牌,触发401错误。Postman能正常访问是因为手动添加了Bearer请求头,而MVC页面请求不会自动将Cookie令牌注入请求头。

最优解决方案

既然选择HttpOnly Cookie存储令牌(更安全,避免XSS窃取),正确做法是配置JwtBearer中间件从Cookie读取令牌,同时完善配置细节:

1. 完善JwtBearer配置

修改MVC项目的身份验证配置,添加Cookie令牌读取逻辑:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        var jwtSettings = builder.Configuration.GetSection("Jwt");
        var key = jwtSettings["Key"];
        var issuer = jwtSettings["Issuer"];

        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = false,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = issuer,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)),
            ClockSkew = TimeSpan.Zero // 关闭时钟偏移,严格校验令牌过期时间
        };

        // 从Cookie读取令牌,兼容无Bearer头的场景
        options.Events = new JwtBearerEvents
        {
            OnMessageReceived = context =>
            {
                // 优先从Cookie获取令牌,仅当请求头无Bearer令牌时生效
                var token = context.Request.Cookies["AccessToken"];
                if (!string.IsNullOrEmpty(token) && string.IsNullOrEmpty(context.Request.Headers["Authorization"]))
                {
                    context.Token = token;
                }
                return Task.CompletedTask;
            },
            // 可选:添加过期令牌的响应头标识,方便前端处理刷新逻辑
            OnAuthenticationFailed = context =>
            {
                if (context.Exception is SecurityTokenExpiredException)
                {
                    context.Response.Headers.Append("Token-Expired", "true");
                }
                return Task.CompletedTask;
            }
        };
    });

2. 确保中间件顺序正确

Program.cs中必须按以下顺序注册中间件,否则认证/授权逻辑不生效:

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// 先认证,再授权
app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

3. 验证令牌签名一致性

你提到jwt.io中需勾选secret base64 encoded才显示有效签名,需确认API与MVC的密钥处理完全一致:

  • API的GetSigningCredentials方法使用Encoding.UTF8.GetBytes(key),MVC中同样处理,这是正确的。若jwt.io验证异常,大概率是密钥输入时的格式问题(如多余空格),确保两端密钥完全匹配即可。

4. 角色授权校验

若仍存在角色授权问题,可在控制器中打印当前用户角色排查:

public IActionResult Privacy()
{
    var userRoles = User.Claims
        .Where(c => c.Type == ClaimTypes.Role)
        .Select(c => c.Value);
    // 调试时输出角色,确认令牌中的角色已正确解析
    return View();
}

方案优势

  • 保留HttpOnly Cookie的安全性,防范XSS攻击
  • 基于官方中间件扩展实现,符合ASP.NET Core身份验证规范
  • 兼容手动传入Bearer令牌的场景(如Postman测试)

内容的提问来源于stack exchange,提问作者micex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:48:11