我有一个使用两种身份验证方案的 .NET 核心 WebAPI,第一个是 AAD,第二个是 identityserver4
services.AddAuthentication(authOptions =>
{
authOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
authOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
authOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer()//configured below for id4
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
//AAD options
services.Configure<JwtBearerOptions>(
AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
};
});
//id4 options
services.Configure<JwtBearerOptions>(
JwtBearerDefaults.AuthenticationScheme, options =>
{
options.Authority = "https://****/identity";
options.Audience = Constants.Audience;
options.MetadataAddress = "https://****/identity/.well-known/openid-configuration";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme,AzureADDefaults.BearerAuthenticationScheme) //added both
.Build();
});
我目前在我的 startup.cs 中使用此配置,当 identityserver4 主机关闭时,我无法授权 Azure 活动目录颁发的令牌(整个令牌验证失败),这是我在日志中看到的
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://****/identity/.well-known/openid-configuration'.
---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://****/identity/.well-known/openid-configuration'.
---> System.Net.Http.HttpRequestException: nodename nor servname provided, or not known
---> System.Net.Sockets.SocketException (0xFFFDFFFF): nodename nor servname provided, or not known
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
如何处理此类异常,我看到一个问题here但我认为会有解决方法。
首先,AddJWtBearer,如果在第一个令牌到达时无法到达发现端点,将会抱怨。我在我的系统中实施的一个选项是添加一个中间件来阻止传入请求到达它,直到它可以确保 IdentityServer 可以到达。实施起来并不难。
它可以看起来像这样:
如果 AddJwtBearer(通过 ConfigurationManager)之后无法到达发现端点,它将重用现有配置。它默认每 24 小时刷新一次。如果失败,重试周期为 30 秒。
或者,如果该中间件无法到达 IdentitySerer,则可以从请求中“删除”承载令牌。这样请求就不会触发 AddJwtBearer。
或者,您可以从 GitHub 下载 AddJwtBearer 的源码,然后手动修补 authenticate 方法。
为了补充这个答案,我写了一篇博客文章,详细介绍了这个主题: 解决 ASP.NET Core 中的 JwtBearer 身份验证问题