Microsoft.AspNetCore.Authentication.OpenIdConnect /oauth2/authorize 端点形式 - redirect_uri 错误

Microsoft.AspNetCore.Authentication.OpenIdConnect /oauth2/authorize endpoint form - redirect_uri error

我有一个应用程序(.NET 5.0 ASP Net Core)应用程序,我正在尝试将其部署到 AWS Amazon Linux 2 服务器。看起来部署的所有方面都很好,除了 AWS Congnito 和 Microsoft.AspNetCore.Authentication.OpenIdConnect 的授权。在 dev/local 中一切正常,问题只会在产品部署中出现。

问题表现为“请求的页面遇到错误”。尝试登录时在 Hosted UI 中的 https://auth.<mydomain>.com/error?error=redirect_mismatch&client_id=<myclientid>。我已经确认并再次确认回调 URL(s) 设置正确:https://sub.domain.com/signin-oidc, https://localhost:5001/signin-oidc.

我的应用程序位于 http://localhost:5000 上 运行,位于 apache 反向代理后面。我怀疑 Apache 和 Kestrel 之间路径的非 HTTPS 部分是问题所在。

我注意到 Microsoft.AspNetCore.Authentication.OpenIdConnect 在 redirect_uri 值中缺少 https,它创建为它调用的 /oauth2/authorize 端点的一部分。

这是我在 Dev 中看到的(没有问题):

这是我在部署时看到的,注意 redirect_uri 是 http:

在应用程序客户端设置中,我无法将 signin-oidc 端点设置为使用 HTTP。

我的配置服务:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddOpenIdConnect(options =>
            {
                options.ResponseType = "code";
                options.ResponseType = Configuration["Authentication:Cognito:ResponseType"];
                options.MetadataAddress = Configuration["Authentication:Cognito:MetadataAddress"];
                options.ClientId = Configuration["Authentication:Cognito:ClientId"];
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    RoleClaimType = "cognito:groups"
                };
                options.Events = new OpenIdConnectEvents
                {
                    OnTicketReceived = e =>
                    {
                        e.ReturnUri = string.Format("/Home/CheckProfile?url={0}", HttpUtility.UrlEncode(e.ReturnUri));
                        return Task.CompletedTask;
                    }
                };
            });
        }

那么,为什么 Microsoft.AspNetCore.Authentication.OpenIdConnect 在生成 /oauth2/authorize 端点的 redirect_uri 值时使用 HTTP。那是我需要在某处调整的东西吗?而且,这似乎是导致我的整体 https://auth.<mydomain>.com/error?error=redirect_mismatch&client_id=<myclientid> 问题的核心问题吗?

这里的核心问题是反向代理; Kestrel 运行 落后于 Apache。虽然我在过去几年中经常使用此设置(与 certbot),但我以前没有将它与 OIDC 身份验证方案一起使用。问题是 apache 的 https 终止以及 Apache 和 Kestrel 之间的 http 传输。 OIDC 身份验证方案(在我的例子中由 AWS Cognito 支持)需要端到端 https。

“作为 /oauth2/authorize 端点的一部分创建的 redirect_uri 值中缺少 https”只是我发现的众多问题中的第一个。我想出了一个解决这个问题的方法:

.AddOpenIdConnect(options =>
{
   ...
   options.Events = new OpenIdConnectEvents
   {
      ...
      OnRedirectToIdentityProvider = async n =>
      {
         n.ProtocolMessage.RedirectUri = n.ProtocolMessage.RedirectUri.Replace("http://", "https://");
         await Task.FromResult(0);
      }
   };
});

但这只解决了更改 redirect_uri 原型的狭隘问题;然后出现其他 cookie SameSite=None/Secure/http 问题。

至此,我已经成功地在 80 和 443 上直接暴露了 Kestrel。我意识到这是否是一个谨慎的想法值得商榷,但它目前和今天(2021 年夏季在 .NET 5.0 上)对我有用) 似乎 Kestrel 已经成熟到不再是“只在开发中这样做!”的地步。工具。

我发现这两篇文章都非常有帮助:

https://swimburger.net/blog/dotnet/how-to-run-aspnet-core-as-a-service-on-linux

https://thecodeblogger.com/2021/05/07/certificates-and-limits-for-asp-net-core-kestrel-web-server/

更好的答案。虽然“Kestrel 暴露于世界”的答案有效,但我最终弄清楚了如何使反向代理与 Cognito 一起工作。

在反向代理中,我最终设置了“'https' env=HTTPS”,如下所示:

<VirtualHost *:*>
    RequestHeader set "X-Forwarded-Proto" 'https' env=HTTPS
</VirtualHost>

我还重新安排了我的 Prod Configure(...) 如下:


if (env.IsDevelopment())
{
   app.UseDeveloperExceptionPage();
   app.UseForwardedHeaders();
}
else
{
   app.UseExceptionHandler("/Home/Error");
   app.UseForwardedHeaders();
   app.Use((ctx, next) =>
   {
      ctx.Request.Host = new HostString("sub.domain.com");
      ctx.Request.Scheme = "https";
      return next();
   });
   app.UseHsts();
}