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

.NET 6中JWT Bearer Token授权失败(401 Unauthorized)求助

.NET 6 JWT授权401错误排查方向

以下是针对你遇到的「已生成JWT Token但访问带[Authorize]特性的接口返回401」问题的具体排查点:

1. 严格校验Issuer/Audience的完全一致性

  • 确保生成Token时的Issuer、Program.cs中验证的ValidIssuer、appsettings.json中的JWT:Issuer三者完全匹配,包括协议(http/https)、端口、是否带结尾斜杠,甚至大小写。比如你修改为https://localhost:7139后,要检查三处是否都统一为这个值,不能一处是http另一处是https。
  • 同理Audience(JWT:Audience)也要保持完全一致,你的配置中是user,确认生成和验证逻辑都使用这个值。

2. 检查请求中Token的携带方式

  • 访问接口时,必须在请求头中添加Authorization字段,格式为Bearer <你的Token>,注意Bearer和Token之间有一个空格。
  • 排查是否存在字段拼写错误(比如把Authorization写成Auth),或者Token被截断、复制不全的情况。

3. 确认Secret的完全匹配

  • 生成Token时使用的JWT:Secret和验证时的Secret必须完全一致,包括字符大小写、特殊符号、前后空格。你当前用的是this-is-just-a-strong-key,检查三处代码(GenerateJWTToken、Program.cs、appsettings.json)是否都引用了同一个配置,且配置值无额外空格。
  • 注意:如果Secret包含非ASCII字符,需将Encoding.ASCII.GetBytes改为Encoding.UTF8.GetBytes,避免字符编码不一致导致签名验证失败。

4. 解析Token验证核心字段有效性

  • 把生成的Token复制到本地解析工具(如jwt.io,仅本地解析无需上传),检查以下内容:
    • Payload中的iss是否与配置的Issuer完全一致
    • aud是否为user
    • exp是否未过期(当前时间早于exp对应的时间)
    • 签名栏是否显示「Signature verified」,如果未验证通过,说明Secret不匹配或Token被篡改。

5. 确认中间件注册顺序

  • 在Program.cs中,必须先调用app.UseAuthentication(),再调用app.UseAuthorization(),如果顺序颠倒,授权逻辑会在认证之前执行,导致401错误。

6. 检查HTTPS相关配置矛盾

  • 你的Program.cs中设置了options.RequireHttpsMetadata = false,如果服务实际运行在HTTPS环境(比如你用的https://localhost:7139),此配置本身没问题,但要确保请求是通过HTTPS发送的,避免协议不匹配。

附你提供的代码片段

AuthController.cs(生成Token逻辑)

private async Task<AuthResultVM> GenerateJWTToken(User user)
{
    var authClaims = new List<Claim>()
    {
        new Claim(ClaimTypes.Name, user.UserName),
        new Claim(ClaimTypes.NameIdentifier, user.Id),
        new Claim(JwtRegisteredClaimNames.Email, user.Email),
        new Claim(JwtRegisteredClaimNames.Sub, user.Email),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
    };

    var authSignInKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration["JWT:Secret"]));

    var token = new JwtSecurityToken(
        issuer: _configuration["JWT:Issuer"],
        audience: _configuration["JWT:Audience"],
        expires: DateTime.UtcNow.AddDays(7),
        claims: authClaims,
        signingCredentials: new SigningCredentials(authSignInKey, SecurityAlgorithms.HmacSha256)
    );

    var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);

    var response = new AuthResultVM()
    {
        Token = jwtToken,
        ExpiresAt = token.ValidTo
    };

    return response;
}

AccountController(授权接口)

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class AccountController : ControllerBase
{
    private readonly IMapper _mapper;
    public AccountController(IMapper mapper)
    {
        _mapper = mapper;
    }
    [HttpGet]
    public ActionResult Get()
    {
        return Ok("This is the AccountContoller");
    }
}

appsettings.json(配置文件)

"JWT": {
  "Secret": "this-is-just-a-strong-key",
  "Audience": "user",
  "Issuer": "http://localhost:44347"
  // 已将Issuer修改为localhost:7139,但仍出现401错误
}

Program.cs(认证配置)

// 其他代码
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.SaveToken = true;
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["JWT:Secret"])),

        ValidateIssuer = true,
        ValidIssuer = builder.Configuration["JWT:Issuer"],

        ValidateAudience = true,
        ValidAudience = builder.Configuration["JWT:Audience"],
    };
});

//其他代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:29:57