c# - 如果身份服务器发现文档无法访问,则处理错误
问题描述
我有一个使用两种身份验证方案的 .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)
如何处理此类异常,我在这里看到了一个问题,但我认为会有一种解决方法。
解决方案
首先,AddJWtBearer,如果在第一个令牌到达时无法到达发现端点,则会抱怨。我在我的系统中实现的一个选项是添加一个中间件,该中间件阻止传入的请求到达它,直到它可以确保 IdentityServer 是可访问的。实施起来并不难。
它看起来像这样:
如果 AddJwtBearer(通过 ConfigurationManager)之后无法到达发现端点,它将重用现有配置。默认情况下,它将每 24 小时刷新一次。如果失败,重试周期为 30 秒。
或者,如果该中间件无法访问 IdentitySerer,则可以从请求中“删除”承载令牌。这样请求就不会触发 AddJwtBearer。
或者,您可以从 GitHub 下载 AddJwtBearer 的源代码,然后手动修补 authenticate 方法。
推荐阅读
- node.js - 使用节点 js SDK 或 API 将附件添加到 Xero 中的发票
- javascript - 如何将此单个幻灯片脚本转换为多个幻灯片
- javascript - 有没有像 Promise.all() 这样的函数,但即使在一个失败之后也会运行所有的 Promise?
- flutter - 多次执行语句
- python - 生成所有可能的井字棋棋盘位置
- python - 寻找情节的时期
- angular - 如何在 Angular 中使用 EventEmitter 将 JSON 数据从 ChildComponent 传递到 AppComponent
- python - 错误:“pygame.Surface”对象不可调用
- c - macOS 上使用什么时钟返回 SO_TIMESTAMP 的值?
- css - 如何根据rails中的用户设置动态更改tailwind-config.js