今天我正在检查是否可以将我的应用程序迁移到.NET 8。起初一切正常,当我尝试登录时,我在控制台中收到以下错误:
验证令牌失败。
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10506:签名验证失败。用户定义的“委托”指定于 TokenValidationParameters 未返回“Microsoft.IdentityModel.JsonWebTokens.JsonWebToken”, 但在验证令牌时返回“System.IdentityModel.Tokens.Jwt.JwtSecurityToken”
我的客户正在使用 PingID 的定制实现。使用内省来验证令牌,这就是我编写自定义令牌验证器的原因:
public class PingTokenValidator : ISecurityTokenValidator
{
private readonly IConfiguration configuration;
private readonly ILogger log;
private readonly OpenIdConnectConfiguration openIdConnectConfiguration;
private readonly JwtSecurityTokenHandler tokenHandler;
public PingTokenValidator(OpenIdConnectConfiguration openIdConnectConfiguration,
IConfiguration configuration)
{
this.tokenHandler = new();
this.openIdConnectConfiguration = openIdConnectConfiguration;
this.configuration = configuration;
this.log = Log.ForContext<PingTokenValidator>();
}
public bool CanReadToken(string securityToken)
{
return true;
}
public ClaimsPrincipal ValidateToken(string securityToken,
TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
try
{
var principal = this.tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken);
if (tokenExistInCache && cachedToken == securityToken)
{
return principal;
}
if (!this.IsValid(securityToken))
{
throw new SecurityTokenValidationException("Token not authorised by PingID.");
}
return principal;
}
catch (Exception e)
{
this.log.Error(e, "Error validating JWT token");
throw;
}
}
public bool CanValidateToken { get; }
public int MaximumTokenSizeInBytes { get; set; } = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
private bool IsValid(string securityToken)
{
var options = new RestClientOptions
{
Authenticator = new HttpBasicAuthenticator(this.configuration["FDID:UserId"]!, this.configuration["FDID:Secret"]!)
};
var client = new RestClient(options);
var request = new RestRequest(this.openIdConnectConfiguration.IntrospectionEndpoint, Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "urn:pingidentity.com:oauth2:grant_type:validate_bearer");
request.AddParameter("token", securityToken);
var response = client.Execute(request);
if (!response.IsSuccessful)
{
this.log.Error(response.ErrorException, "Error validating JWT token. Response message: {@TokenIntrospectionMessage}", response.Content);
return false;
}
if (string.IsNullOrWhiteSpace(response.Content))
{
this.log.Error("Ping returned empty response: {@IntrospectionResponse}", response);
return false;
}
var tokenSummary = JsonSerializer.Deserialize<PingTokenSummary>(response.Content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return tokenSummary is
{
Active: true
};
}
}
我一直在寻找其他可以用来代替
ISecurityTokenValidator
的接口,但没有成功。我是不是错过了什么?
看来微软现在对从
TokenValidationParameters.SignatureValidator
返回的确切类型有更严格的要求。您正在这样的方法中进行设置
authenticationBuilder.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = false,
ValidateIssuerSigningKey = false,
SignatureValidator = delegate (string token, TokenValidationParameters parameters)
{
var jwt = new JsonWebToken(token); // here was JwtSecurityToken
if (parameters.ValidateIssuer && parameters.ValidIssuer != jwt.Issuer)
return null;
return jwt;
},
ValidIssuer = configuration.JwtIssuer,
ValidAudience = configuration.JwtAudience,
RequireSignedTokens = false
};
#if DEBUG
options.IncludeErrorDetails = true;
#endif
}
);
SignatureValidator 委托中的旧代码返回
JwtSecurityToken
的实例,当我将其更改为“JsonWebToken”时,它开始工作。请注意,正如错误消息所正确表明的那样,每个都来自不同的命名空间。
希望它对你也有用。