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

为端点添加[authorize]后返回401,JWT认证异常求助

JWT认证返回401未授权排查求助

给API端点添加[Authorize]特性后,访问始终返回401未授权错误。JWT令牌在jwt.io验证正常,但后端中间件日志显示认证失败:先提示“Token is null or empty”,随后抛出SecurityTokenMalformedException(提示JWT格式不正确),内部嵌套MissingMethodException,找不到Microsoft.IdentityModel.Tokens.Base64UrlEncoder.UnsafeDecode(System.ReadOnlyMemory1)`方法。以下是相关日志和代码:

中间件日志

Twyt.Twyt.Api.Middleware.RequestLoggingMiddleware: Information: Handling request: GET /api/Post/user/82d3f35b-aa00-453b-80f5-2c06f2063e60

Twyt.Twyt.Api.Middleware.RequestLoggingMiddleware: Information: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4MmQzZjM1Yi1hYTAwLTQ1M2ItODBmNS0yYzA2ZjIwNjNlNjAiLCJqdGkiOiJjYzYwZWNlMi0wZDE0LTQ3NWEtOTcxOC00NWYwMzhiM2VhZmIiLCJleHAiOjE3MjY0MTc1NDksImlzcyI6IlR3eXQiLCJhdWQiOiJUd3l0In0.UN8rtNhp6HI7Ut6ovUOTYBFmYHneHHbN8XblZRZ3PlU
Program: Warning: Token is null or empty
Loaded Assembly '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Diagnostics.StackTrace.dll'
Loading module /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Diagnostics.StackTrace.dll in application domain 1:clrhost
Pdb file for assembly /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Diagnostics.StackTrace.dll was not found or failed to read
Loaded Assembly '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Reflection.Metadata.dll'
Loading module /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Reflection.Metadata.dll in application domain 1:clrhost
Pdb file for assembly /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Reflection.Metadata.dll was not found or failed to read
Loaded Assembly '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Collections.Immutable.dll'
Loading module /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Collections.Immutable.dll in application domain 1:clrhost
Pdb file for assembly /usr/local/share/dotnet/shared/Microsoft.NETCore.App/8.0.8/System.Collections.Immutable.dll was not found or failed to read
Program: Error: Authentication failed: Microsoft.IdentityModel.Tokens.SecurityTokenMalformedException: IDX14100: JWT is not well formed, there are no dots (.).
The token needs to be in JWS or JWE Compact Serialization Format. (JWS): 'EncodedHeader.EndcodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.
 ---> System.MissingMethodException: Method not found: 'Byte[] Microsoft.IdentityModel.Tokens.Base64UrlEncoder.UnsafeDecode(System.ReadOnlyMemory`1<Char>)'.
   at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken.ReadToken(String encodedJson)
   at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken..ctor(String jwtEncodedString)
   at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ReadToken(String token, TokenValidationParameters validationParameters)
   --- End of inner exception stack trace ---
Program: Warning: OnChallenge error: invalid_token
Twyt.Twyt.Api.Middleware.RequestLoggingMiddleware: Information: Finished handling request. Status code: 401
Twyt.Twyt.Api.Middleware.RequestLoggingMiddleware: Warning: Unauthorized access attempt: GET /api/Post/user/82d3f35b-aa00-453b-80f5-2c06f2063e60

Program.cs中的JWT认证配置

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{           
    var key = Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"] ?? throw new InvalidOperationException("JWT Key is not configured"));

    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["Jwt:Issuer"] ?? throw new InvalidOperationException("JWT Issuer is not configured"),
        ValidAudience = builder.Configuration["Jwt:Audience"] ?? throw new InvalidOperationException("JWT Audience is not configured"),
        IssuerSigningKey = new SymmetricSecurityKey(key)
    };
    options.IncludeErrorDetails = true; 
    options.Events = new JwtBearerEvents
    {
        OnAuthenticationFailed = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
            logger.LogError("Authentication failed: {Exception}", context.Exception.ToString());
            return Task.CompletedTask;
        },
        OnChallenge = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
            logger.LogWarning("OnChallenge error: {0}", context.Error);
            return Task.CompletedTask;
        },
        OnMessageReceived = context =>
        {
            var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
            var token = context.Token;

            if (string.IsNullOrEmpty(token))
            {
                logger.LogWarning("Token is null or empty");
                return Task.CompletedTask;
            }

            // Log the raw token for debugging
            logger.LogInformation("Token received: {Token}", token);

            return Task.CompletedTask;
        }
    };
});
builder.Services.AddAuthorization();

GenerateJwtToken令牌生成函数

public async Task<string> GenerateJwtToken(User user)
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

    var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.UserId.ToString()),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            };

    var token = new JwtSecurityToken(
                _configuration["Jwt:Issuer"],
                _configuration["Jwt:Audience"],
                claims,
                expires: DateTime.Now.AddHours(2),
                signingCredentials: credentials
            );

    return new JwtSecurityTokenHandler().WriteToken(token);
}

排查解决方案

  1. 统一NuGet包版本
    核心错误MissingMethodException表明运行时找不到指定方法,大概率是Microsoft.IdentityModel.Tokens、Microsoft.AspNetCore.Authentication.JwtBearer等相关包版本与.NET 8 runtime不兼容。

    • 执行dotnet list package查看当前包版本,确保所有IdentityModel相关包版本统一,且适配.NET 8(建议使用8.x系列版本)。
    • 通过dotnet add package <PackageName> --version <CompatibleVersion>命令升级或统一包版本,比如:
      dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 8.0.8
      dotnet add package Microsoft.IdentityModel.Tokens --version 8.0.2
      
  2. 修复令牌读取逻辑
    日志显示请求头存在Bearer令牌,但OnMessageReceived中context.Token为空,说明中间件未正确提取令牌。可以手动从请求头获取并赋值:

    OnMessageReceived = context =>
    {
        var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
        var authHeader = context.HttpContext.Request.Headers.Authorization.FirstOrDefault();
        if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
        {
            context.Token = authHeader.Substring("Bearer ".Length).Trim();
            logger.LogInformation("Token received: {Token}", context.Token);
        }
        else
        {
            logger.LogWarning("Token is null or empty");
        }
        return Task.CompletedTask;
    }
    
  3. 验证令牌传输完整性
    确认Swagger发送请求时,Authorization头严格遵循Bearer <Token>格式,无多余空格、换行或特殊字符。可以直接复制日志中的令牌到jwt.io再次验证,排除传输过程中的篡改问题。

内容的提问来源于stack exchange,提问作者Abdou El Mesnaoui

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:02:33