用的是 ASP.NET Core 9.0 与 Cnblogs.IdentityServer4 4.3.0,带 PAT(Personal Access Token) 请问 api 使出现下面的错误:
2025-05-04 11:11:34.755 +08:00 [INF] Failed to validate the token.
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.EncodedPayload.EncodedSignature'. (JWE): 'EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag'.
at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken.ReadToken(ReadOnlyMemory`1 encodedTokenMemory)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebToken..ctor(String jwtEncodedString)
at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ReadToken(String token, TokenValidationParameters validationParameters)
对应的 Authentication 配置代码:
services.AddAuthentication("token")
// PAT or reference token
.AddOAuth2Introspection("introspection", options =>
{
options.Authority = webApiOptions.Authority;
options.ClientId = webApiOptions.ApiName;
options.ClientSecret = webApiOptions.ApiSecret;
options.EnableCaching = true;
options.DiscoveryPolicy.ValidateIssuerName = false;
options.DiscoveryPolicy.RequireHttps = false;
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("Bearer", options =>
{
options.Authority = webApiOptions.Authority;
options.Audience = webApiOptions.ApiName;
options.RequireHttpsMetadata = webApiOptions.RequireHttpsMetadata;
});
带 PAT 发请求时,也用的是 Bearer 验证请求头,也会走 AddJwtBearer("Bearer")
对应的 JwtBearerHandler
Authorization: Bearer <token>
解决这个问题,需要通过 ForwardDefaultSelector 转发请求到 introspection
scheme
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer("Bearer", options =>
{
options.Authority = webApiOptions.Authority;
options.Audience = webApiOptions.ApiName;
options.RequireHttpsMetadata = webApiOptions.RequireHttpsMetadata;
options.ForwardDefaultSelector = Selector.ForwardReferenceToken("introspection");
});
ForwardReferenceToken 对应的实现代码
// Copy from IdentityModel.AspNetCore.AccessTokenValidation
public static class Selector
{
public static Func<HttpContext, string> ForwardReferenceToken(string introspectionScheme = "Introspection")
{
return Select;
string Select(HttpContext context)
{
var (text, text2) = GetSchemeAndCredential(context);
if (text.Equals("Bearer", StringComparison.OrdinalIgnoreCase) && !text2.Contains("."))
{
return introspectionScheme;
}
return null;
}
}
public static (string, string) GetSchemeAndCredential(HttpContext context)
{
string text = context.Request.Headers["Authorization"].FirstOrDefault();
if (string.IsNullOrEmpty(text))
{
return (string.Empty, string.Empty);
}
string[] array = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (array.Length != 2)
{
return (string.Empty, string.Empty);
}
return (array[0], array[1]);
}
}