ASP.NET Core部署在WAF/网关后Oracle OAuth认证异常问题
我有一个前端基于JavaScript、后端用C# .NET开发的应用,采用Oracle IDCS的OAuth协议做身份认证。原本运行正常,但现在后端部署在可访问公网的API网关/WAF之后:公网地址是public-host.com,网关会把公网请求转发到后端实际接收请求的内部地址private-host.io,导致后端“识别”的自身部署地址和实际公网地址不一致。
当前后端调用Oracle时,使用的OAuth参数redirect_uri是错误的,示例(未URL编码):https://idcs-xxx.identity.oraclecloud.com/oauth2/v1/authorize?client_id=...&scope=...&...&redirect_uri=http://private-host.io/authorization_code/callback&...
公网用的是https,但内部地址用的是http。
尝试的修复代码
我尝试通过以下代码修改redirect_uri:
services .AddAuthentication(options => { /*...*/ }) .AddOAuth("Oracle", options => { options.Events = new OAuthEvents { OnRedirectToAuthorizationEndpoint = context => { // 将context.RedirectUri中的redirect_uri参数替换为公网地址 // 也就是把"http://internal-host.io/"替换成"https://public-host.com/" // context.RedirectUri是完整的重定向URL,比如:https://idcs-xxx.identity.oraclecloud.com/oauth2/v1/authorize?client_id=...&scope=...&...&redirect_uri=http://internal-host.io/authorization_code/callback // 这里是伪代码,实际需要处理URL编码问题 context.RedirectUri = context.RedirectUri.Replace("http://internal-host.io/", "https://public-host.com/"); context.Response.Redirect(context.RedirectUri); return Task.CompletedTask; } }; });
修改后的错误
修改后,OAuth请求使用了正确的redirect_uri,Oracle认证成功并回调到正确地址https://public-host.com/authorization-code/callback?code=XXX,但C#代码抛出两个错误:
第一个错误:
An error was encountered while handling the remote login. Correlation failed. Microsoft.AspNetCore.Authentication.AuthenticationFailureException: at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1+<HandleRequestAsync>d__12.MoveNext (Microsoft.AspNetCore.Authentication, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
第二个错误:
Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote login. ---> Microsoft.AspNetCore.Authentication.AuthenticationFailureException: OAuth token endpoint failure: invalid_redirect_uri;Description=Client XXXX requested an invalid redirect URL: http://internal-host.io:443/authorization-code/callback.
(注意错误中的http://internal-host.io)
我怀疑虽然在OnRedirectToAuthorizationEndpoint中修改了redirect_uri,但OAuth处理逻辑仍然期望使用内部地址,导致地址不一致引发失败。
补充配置信息
后端OAuth的基础配置如下:
services.AddAuthentication(options => {...}) .AddOAuth("Oracle", options => { Uri apiAddress = configuration.OracleApiAddress; options.AuthorizationEndpoint = $"{apiAddress}/oauth2/v1/authorize"; options.Scope.Add("openid"); options.Scope.Add("urn:opc:idm:__myscopes__"); options.CallbackPath = new PathString("/authorization-code/callback"); options.ClientId = configuration.OracleApplicationId; options.ClientSecret = configuration.OracleApplicationSecret; options.TokenEndpoint = $"{apiAddress}/oauth2/v1/token"; options.UserInformationEndpoint = $"{apiAddress}/oauth2/v1/userinfo"; // ... }
核心问题分析
问题出在两个关键环节:
- Token请求的redirect_uri不匹配:仅修改授权跳转时的redirect_uri无效,调用Token端点换取令牌时,后端仍用内部地址生成redirect_uri,导致Oracle IDCS校验失败。
- 关联Cookie不匹配:ASP.NET Core远程认证生成的关联Cookie包含内部地址,公网回调请求到达时,Cookie地址与实际请求地址不一致,触发
Correlation failed错误。
具体修复步骤
1. 配置转发头识别真实请求地址(必做)
后端部署在网关后,需让ASP.NET Core从网关转发头中获取真实的公网协议和主机名。在Program.cs中添加以下配置:
builder.Services.Configure<ForwardedHeadersOptions>(options => { // 开启转发头解析,获取真实协议和主机 options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; // 添加网关的内部IP到信任列表,生产环境建议精准配置 options.KnownProxies.Add(IPAddress.Parse("网关内部IP")); // 若网关是网段,可改用以下配置 // options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("网关网段"), 24)); }); // 必须在UseRouting之前启用转发头解析 app.UseForwardedHeaders(); app.UseRouting();
配置后,ASP.NET Core会自动使用公网的https协议和public-host.com主机名生成redirect_uri,无需手动替换。
2. 强制Token请求使用公网redirect_uri(可选补充)
若转发头配置后仍存在Token校验问题,可在OAuth事件中强制指定Token请求的redirect_uri:
.AddOAuth("Oracle", options => { // 原有配置... options.Events = new OAuthEvents { OnTokenRequest = context => { // 替换Token请求中的redirect_uri为公网地址 context.Request.Parameters["redirect_uri"] = "https://public-host.com/authorization-code/callback"; return Task.CompletedTask; } }; });
3. 验证关联Cookie生成逻辑
转发头配置生效后,关联Cookie会自动使用公网地址生成。若仍有Correlation failed错误,可手动指定回调地址:
.AddOAuth("Oracle", options => { // 原有配置... options.Events.OnRedirectToAuthorizationEndpoint = context => { // 手动设置公网回调地址 context.Properties.RedirectUri = "https://public-host.com/authorization-code/callback"; // 重新组装授权URL var authorizationUrl = QueryHelpers.AddQueryString( options.AuthorizationEndpoint, new Dictionary<string, string> { ["client_id"] = options.ClientId, ["redirect_uri"] = context.Properties.RedirectUri, ["response_type"] = "code", ["scope"] = string.Join(" ", options.Scope), ["state"] = context.Properties.GetTokenValue("state"), ["nonce"] = context.Properties.GetTokenValue("nonce") }); context.Response.Redirect(authorizationUrl); return Task.CompletedTask; }; });
额外注意事项
- 确保Oracle IDCS的客户端配置中,已将
https://public-host.com/authorization-code/callback添加到允许的重定向URI列表。 - 网关必须正确转发
X-Forwarded-Proto(值为https)和X-Forwarded-Host(值为public-host.com)请求头,否则转发头配置无法生效。
内容的提问来源于stack exchange,提问作者user1713059

