gpt4 book ai didi

c# - NET5 JWT 不记名身份验证不识别 SSL 证书

转载 作者:行者123 更新时间:2023-12-04 22:36:34 29 4
gpt4 key购买 nike

我有一个使用 Grpc 的 .NET 5 WebApi 和一个在 YARP 反向代理后面运行的 IdentityServer4。反向代理正在使用有效的 Let's Encrypt 证书,并将请求路由到正在监听 localhost:port 并使用自签名证书的另外两个。它们在 Linux Mint 20.1 上运行,我使用 OpenSSL 创建了自签名证书并将其添加到 /usr/local/share/ca-certificates/extra并运行 update-ca-certificates更新证书存储。
一切运行良好,YARP 识别用于路由请求的 sefl 签名证书,但对需要授权的 WebApi 的请求会抛出此异常:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMCHFQCVF5UE", Request id "0HMCHFQCVF5UE:0000000B": An unhandled exception was thrown by the application.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: NotTimeValid
at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
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)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Grpc.AspNetCore.Web.Internal.GrpcWebMiddleware.HandleGrpcWebRequest(HttpContext httpContext, ServerGrpcWebMode mode)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
我正在使用 Microsoft.AspNetCore.Authentication.JwtBear 5.0.11,这似乎就是它的来源。该错误似乎表明证书上的时间有问题,但使用 OpenSSL 检查非早于和非晚于日期都可以。
这是它在启动时的设置方式:
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = appSettings.Authorization.Authority;
options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
options.TokenValidationParameters.ValidateAudience = false;
});
我尝试同时使用 "https://localhost:port""https://real.hostname"对于管理局来说,结果是一样的。我也尝试使用 options.RequireHttpsMetadata = false;但它没有效果,我也不想切换到普通的http。
我还尝试使用相同的证书在我的 Windows 机器上运行相同的设置,并且在那里一切正常。什么可能导致不同的行为,我如何获得有关它实际尝试验证的证书以及它如何确定错误的更多信息?

最佳答案

我设法找出原因并修复它。
原因

  • Microsoft.AspNetCore.Authentication.JwtBearer实际上对 IdentityServer4 的调用不是 1 次而是 2 次: 1 次到 /.well-known/openid-configuration获取配置,然后调用 jwks_uri 中返回的端点之前的回应。第一个电话是 localhost:port端点使用自签名证书并正常工作,但第二个是 realdomain使用 Let's Encrypt 证书的端点并因 OP 中的错误而失败。
  • Let's Encrypt 证书链中有一个过期的证书:它使用 DST Root CA X3 而不是 ISRG Root X1(更多信息:https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/)

  • 修复使用不同域的调用
    选项 1 - 在 IdentityServer4 中修复它
    这可以通过更改 Startup.cs 中的 IdentityServer4 原点来实现。 :
            app.Use(async (ctx, next) =>
    {
    ctx.SetIdentityServerOrigin("origin");
    await next();
    });
    选项 2 - 在 API jwt 授权配置中修复它
    这需要实现您自己的配置管理器:
    public class CustomConfigurationManager : IConfigurationManager<OpenIdConnectConfiguration>
    {
    private readonly string authority;
    private readonly string authorityReturnedOrigin;

    public CustomConfigurationManager(string authority, string authorityReturnedOrigin)
    {
    this.authority = authority;
    this.authorityReturnedOrigin = authorityReturnedOrigin;
    }
    public async Task<OpenIdConnectConfiguration> GetConfigurationAsync(CancellationToken cancel)
    {
    var httpClient = new HttpClient();

    var request = new HttpRequestMessage
    {
    RequestUri = new Uri($"{authority}/.well-known/openid-configuration"),
    Method = HttpMethod.Get
    };

    var configurationResult = await httpClient.SendAsync(request, cancel);
    var resultContent = await configurationResult.Content.ReadAsStringAsync(cancel);
    if (configurationResult.IsSuccessStatusCode)
    {
    var config = OpenIdConnectConfiguration.Create(resultContent);
    var jwks = config.JwksUri.Replace(authorityReturnedOrigin, authority);
    var keyRequest = new HttpRequestMessage
    {
    RequestUri = new Uri(jwks),
    Method = HttpMethod.Get
    };
    var keysResposne = await httpClient.SendAsync(keyRequest, cancel);
    var keysResultContent = await keysResposne.Content.ReadAsStringAsync(cancel);
    if (keysResposne.IsSuccessStatusCode)
    {
    config.JsonWebKeySet = new JsonWebKeySet(keysResultContent);
    var signingKeys = config.JsonWebKeySet.GetSigningKeys();
    foreach (var key in signingKeys)
    {
    config.SigningKeys.Add(key);
    }
    }
    else
    {
    throw new Exception($"Failed to get jwks: {keysResposne.StatusCode}: {keysResultContent}");
    }

    return config;
    }
    else
    {
    throw new Exception($"Failed to get configuration: {configurationResult.StatusCode}: {resultContent}");
    }
    }

    public void RequestRefresh()
    {
    // if you are caching the configuration this is probably where you should invalidate it
    }
    }
    然后替换 Startup.cs 中的默认配置管理器:
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
    options.Authority = appSettings.Authorization.Authority;
    options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
    options.TokenValidationParameters.ValidateAudience = false;
    options.ConfigurationManager = new CustomConfigurationManager("authority", "authorityReturnedOrigin");
    }
    修复过期证书链
    这适用于 Linux Mint 20.1,其他发行版可能有不同的处理方式。还建议备份。
  • 确保 openssl 版本高于 1.0.1 或 1.0.2,因为它们可能存在问题(运行 openssl version 进行检查)
  • 运行ls -l | grep ISRG并删除您找到的内容 - 这一步可能不是必需的,但这是我所做的
  • 转至 /etc/ssl/certs
  • 运行ls -l | grep DST并删除你找到的
  • 下载这些文件:isrgrootx1 isrgrootx2 letsencrytptr3
  • 将它们复制到 /etc/ssl/certs请注意,运行证书更新命令,如 update-ca-certificate可能会恢复这一点。

  • 可能有更好的解决方案,也许只是更新到更新的操作系统版本就可以解决它。此问题仅适用于从 Linux Mint 20.1 上运行的代码对 API 进行的 http 调用,在 Windows 上一切正常,通过浏览器访问并没有显示任何 SSL 证书错误。

    关于c# - NET5 JWT 不记名身份验证不识别 SSL 证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69606080/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com