我的ASP.NET核心REST API使用2个身份验证中间件--JWT来验证用户(由ADFS发出的令牌),以及IdentityServer来验证来自其他服务的呼叫。这些中间件的配置如下所示:
JWT
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new X509SecurityKey(federationMetadata.GetSigningCertificate()),
ValidateIssuer = true,
ValidIssuer = federationMetadata.GetIssuerUri().AbsoluteUri,
ValidateAudience = true,
ValidAudience = validAudience,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters
});
Identity Server 4(IDS)
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = dbConfig.IdentityServer.AbsoluteUri,
ScopeName = Configuration.ServiceName,
RequireHttpsMetadata = false
}
我遇到此设置问题:
当用户从ADFS传递令牌时,JWT中间件成功验证令牌。然后,IDS中间件无法验证令牌并引发错误:
IDX10503: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey , KeyId: <MyRsaKey>
这是预期的。如果早期的中间件成功验证了请求,我怎么能告诉IDS中间件不要进行身份验证呢?
我尝试过几件事。在我看来,理想的做法是解决用户已经过身份验证的IDS OnMessageReceived
事件,并告诉IDS中间件不再进一步检查:
JwtBearerEvents = new JwtBearerEvents()
{
OnMessageReceived = async (context) =>
{
if(UserIsAlreadyAuthenticated)
DoNothingMore();
}
}
我尝试捕获IDS OnAuthenticationFailed
事件并跳过中间件:
OnAuthenticationFailed = async (context) =>
{
if (context.Exception is IdentityServerNotAvailableException)
{
context.SkipToNextMiddleware();
}
}
但是我得到了范围验证失败:
Scope validation failed. Return 403.
范围验证在哪里发生?因为似乎IDS中间件中的任何错误都会导致范围验证错误,无论我是否SkipToNextMiddleware
。
如果删除IDS中间件,一切正常。
感谢您的帮助!
编辑:我现在已经解决了范围验证问题。我尝试在IDS中间件上设置ValidateScope = false
选项,但这会在中间件中导致空引用异常;但我发现如果我注释掉ScopeName = Configuration.ServiceName
选项,范围验证问题就解决了(我在自定义处理程序中处理它 - 不太理想)。
仍然需要知道:如果令牌已成功通过身份验证,如何告诉IdentityServer中间件跳过,或者在OnMessageReceived
事件中识别成功的先前身份验证,以便我可以调用SkipToNextMiddleware()
我自己。
谢谢!