反向代理背后的 .NET 6 OAuth 身份验证:挑战时重定向错误 url

.NET 6 OAuth authentication behind reverse proxy: wrong redirect url on challenge

我正在努力在 linux 上托管的 .net 6 razor 页面项目上启用 OAuth2,使用 Apache 作为反向代理。

我在 OAuth 挑战中遇到了关于“redirect_uri”的问题:我得到的 URI 是本地的,而不是通过 reverse-proxy 公开的 URI。 基本上:我到达我的 webapp 访问“login.domain.com”(apache 在本地 kestrel 实例上转发我的请求)。但是一旦我挑战远程登录提供商,我得到

&redirect_uri=http://127.0.0.1:5000/discord-signin

header我的反向代理转发似乎是正确的:

2021-12-19 16:11:44.487 +01:00 [WRN] Header: Accept: ["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Connection: ["keep-alive"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Host: ["127.0.0.1:5000"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: User-Agent: ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Accept-Encoding: ["gzip, deflate, br"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Accept-Language: ["en-US,en;q=0.9,it;q=0.8,de;q=0.7"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Cache-Control: ["max-age=0"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Content-Type: ["application/x-www-form-urlencoded"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Cookie: ["_ga=GA1.2.542637492.1636097135; .AspNetCore.Antiforgery.DTVEdTt8EGg=CfDJ8MlMA29MyfZGjp9AYHEkO4mfg3bwuzIArowPu6tG3DH6IZfzcsAfWAHKHoMi7NeY_dakBIxSHpBv-l_vrIZER2oU06TRVh9A3shL_H6j6gpj_frjZwyNF8qMNpVws7UCg7GGtDZMQIg92GuFtzmo5S0"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Origin: ["login.domain.com"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Referer: ["https://discord.ivao.it/accounts"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Upgrade-Insecure-Requests: ["1"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Content-Length: ["182"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: sec-ch-ua: ["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Microsoft Edge\";v=\"96\""]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: sec-ch-ua-mobile: ["?0"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: sec-ch-ua-platform: ["\"Windows\""]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Sec-Fetch-Site: ["same-origin"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Sec-Fetch-Mode: ["navigate"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Sec-Fetch-User: ["?1"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: Sec-Fetch-Dest: ["document"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Forwarded-Host: ["login.domain.com"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Forwarded-Server: ["login.domain.com"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Original-For: ["127.0.0.1:49194"]

这就是我配置身份验证的方式:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = DiscordAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(opt =>
{
    opt.LoginPath = "/discordauth/signedin";
})
.AddDiscord(opt =>
{
    opt.ClientId = "771681863952891944";
    opt.ClientSecret = "vBvBa3OLkydqkMalLQLHxjGmluqiqflC";
});

我还在 Linux 部署过程中启用了 MS 规定的转发 header 中间件

app.UseCookiePolicy();
app.UseRouting();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthorization();
app.UseAuthentication();

所以,我错过了什么?为什么我的挑战请求生成 redirect_uri 指向本地“localhost:5000”而不是前端 login.domain.com?

在此先感谢您的帮助

好的伙计们。我想我解决了我的错误(因为它是我的坏...)。

自从我的 reverse-proxy 发送了关于前锋的 3 headers:

2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Forwarded-Host: ["login.domain.com"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Forwarded-Server: ["login.domain.com"]
2021-12-19 16:11:44.487 +01:00 [WRN] Header: X-Original-For: ["127.0.0.1:49194"]

我基本上是告诉 .net 使用我的配置处理错误的:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

在这种情况下,httpContext.Request.Host 没有被 ForwardedHeadersMiddleware 覆盖,因为我忘记告诉它也处理主机 header“X-Forwarded-Host”。

这解决了我的问题:

var forwardedHeadersOptions = new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost,
};