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

ASP.NET Core Web API中JWT Bearer令牌认证失败求助

解决ASP.NET Core JWT Bearer令牌验证失败问题

搭建了带有JWT Bearer令牌认证的ASP.NET Core Web API应用,目前令牌验证失败,Postman和Flutter客户端测试均返回401未授权,服务器日志显示认证未通过。

服务器端配置代码

Startup.cs认证配置

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = jwtAuth.Issuer,
            ValidateAudience = true,
            ValidAudience = jwtAuth.Audience,
            ValidateLifetime = true,
            IssuerSigningKey = jwtAuth.GetSecurityKey(),
            ValidateIssuerSigningKey = true,
        };
    });

JWT令牌生成代码

var authClaims = new List<Claim>
{
    new (ClaimTypes.Name, user.UserName!),
    new (JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};

// 未添加角色声明
var token = new JwtSecurityTokenHandler().WriteToken(_jwtConfiguration.GetToken(authClaims));

GetToken方法实现

public JwtSecurityToken GetToken(IEnumerable<Claim> claims)
{
    return new JwtSecurityToken(
        issuer: Issuer,
        audience: Audience,
        notBefore: DateTime.Now,
        claims: claims,
        expires: DateTime.Now.Add(TimeSpan.FromMinutes(LifetimeInMinutes)),
        signingCredentials: new SigningCredentials(GetSecurityKey(), SecurityAlgorithms.HmacSha256));
}

受保护接口代码

[HttpPost("/auth/test")]
[Authorize]
public async Task<ActionResult> TestAuthorization()
{
    return Ok();
}

尝试的另一种令牌生成方式

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(authClaims),
    Expires = DateTime.UtcNow.AddHours(1),
    SigningCredentials = new SigningCredentials(jwtAuth.GetSecurityKey(), SecurityAlgorithms.HmacSha256Signature),
    Issuer = jwtAuth.Issuer,
    Audience = jwtAuth.Audience,
};

var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var accessToken = tokenHandler.WriteToken(securityToken);

服务器错误日志

[23:35:31 INF] Request starting HTTP/1.1 POST http://10.0.2.2:5180/auth/test - 0
[23:35:31 INF] Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
[23:35:31 INF] AuthenticationScheme: Bearer was challenged.
[23:35:31 INF] Request finished HTTP/1.1 POST http://10.0.2.2:5180/auth/test - 0 - 401 0 - 30.5047ms

Flutter客户端请求代码

final url = Uri.parse("${Config.baseUrl}/auth/google");

final Map response = json.decode((await http.post(url, body: {
  'code': signIn?.serverAuthCode,
}))
    .body);

final result = response['result'] as Map;

await http.post(Uri.parse('${Config.baseUrl}/auth/test'), headers: {
  HttpHeaders.authorizationHeader: 'Bearer ${result['accessToken']}',
});

排查与解决步骤

1. 检查中间件顺序

确保在Program.cs(或Startup.cs)中,UseAuthentication和UseAuthorization的顺序正确,必须在UseRouting之后、UseEndpoints之前调用:

app.UseRouting();
app.UseAuthentication(); // 必须在UseAuthorization之前
app.UseAuthorization();
app.UseEndpoints(endpoints => 
{ 
    endpoints.MapControllers(); 
});

2. 统一时间为UTC

生成令牌时使用DateTime.UtcNow替代DateTime.Now,避免时区差异导致的生命周期验证失败:

// 修改GetToken方法中的时间参数
notBefore: DateTime.UtcNow,
expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(LifetimeInMinutes)),

3. 确保签名算法一致

生成令牌和验证时使用相同的签名算法,将GetToken方法中的算法改为SecurityAlgorithms.HmacSha256Signature,与第二种生成方式保持一致:

signingCredentials: new SigningCredentials(GetSecurityKey(), SecurityAlgorithms.HmacSha256Signature)

4. 验证令牌内容

使用jwt.io解析生成的令牌,确认以下内容:

  • iss字段与服务器配置的ValidIssuer完全一致
  • aud字段与服务器配置的ValidAudience完全一致
  • exp字段未过期
  • 签名验证通过(需输入签名密钥)

5. 检查请求头格式

确保客户端发送的Authorization头格式正确,为Bearer {token},无多余空格或拼写错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:07:07