ASP.NET Core 8 Web API JWT Token认证失败(401未授权)求助
问题场景
使用[Authorize]特性保护FastaController的Get端点时,调用会直接返回401 Unauthorized错误;但移除[Authorize]特性后,能通过HttpContext.User正确识别用户身份,说明JWT令牌解析正常,但认证流程未生效。
相关代码与配置
受保护的API控制器
[Authorize] [Route("[controller]")] public class FastaController : Controller { [HttpGet()] public async Task<IActionResult> Get(int page = 1, string search = "", int pageSize = 25) { // 数据获取逻辑 } }
appsettings.json中的JWT配置
"JwtTokenSettings": { "Key": "fc746b61cde4f6665d3f9791446cd5395661860c0075a905ed9810b7391af467", "Issuer": "Comply", "Audience": "comply", "ExpiryHours": 24 }
JWT令牌生成服务
public class JwtTokenService : IJwtTokenService { private readonly IOptions<JwtTokenSettings> jwtTokenSettings; public JwtTokenService(IOptions<JwtTokenSettings> jwtTokenSettings) { this.jwtTokenSettings = jwtTokenSettings; } public string GenerateToken(Guid userId, string userEmail) { string secretKey = jwtTokenSettings.Value.Key; string issuer = jwtTokenSettings.Value.Issuer; string audience = jwtTokenSettings.Value.Audience; var expiryHours = jwtTokenSettings.Value.ExpiryHours; var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()), new Claim(JwtRegisteredClaimNames.Email, userEmail), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var token = new JwtSecurityToken( issuer: issuer, audience: audience, claims: claims, expires: DateTime.UtcNow.AddHours(expiryHours), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } }
Program.cs中的服务配置
var builder = WebApplication.CreateBuilder(args); builder.Services.Configure<JwtTokenSettings>( configuration.GetSection("JwtTokenSettings") ); var jwtSettings = builder.Configuration.GetSection("JwtTokenSettings"); var key = Encoding.UTF8.GetBytes(jwtSettings["Key"]); builder.Services.AddSingleton<IJwtTokenService, JwtTokenService>(); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings["Issuer"], ValidAudience = jwtSettings["Audience"], IssuerSigningKey = new SymmetricSecurityKey(key) }; });
问题原因与解决方案
核心原因
Program.cs中仅配置了认证服务,但未在请求管道中启用认证和授权中间件,导致[Authorize]特性无法触发认证逻辑,直接返回401。
解决方案
- 添加认证与授权中间件到请求管道
在Program.cs的管道配置部分,确保UseAuthentication()和UseAuthorization()在UseRouting()之后、UseEndpoints()之前添加,顺序不能颠倒:
var app = builder.Build(); // 其他中间件(如UseHttpsRedirection) app.UseHttpsRedirection(); app.UseRouting(); // 启用认证和授权中间件 app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.Run();
- 可选:验证Claim类型映射(若用户识别仍有问题)
生成令牌时使用的JwtRegisteredClaimNames.Sub,默认会被JWT中间件映射到ClaimTypes.NameIdentifier,但如果出现映射异常,可手动指定:
- 方式一:在JWT配置中添加Claim类型映射
.AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { // 原有配置 NameClaimType = ClaimTypes.NameIdentifier, RoleClaimType = ClaimTypes.Role }; })
- 方式二:生成令牌时直接使用
ClaimTypes.NameIdentifier
var claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()), new Claim(JwtRegisteredClaimNames.Email, userEmail), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) };
内容的提问来源于stack exchange,提问作者Bill Haack
相关产品推荐
相关产品推荐

