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
相关产品推荐
相关产品推荐

