.NET 4身份认证跳转登录在YARP+Nginx代理下异常
在Azure环境中部署了基础配置的YARP反向代理,请求会先转发至运行ModSecurity规则校验的Nginx反向代理容器,再传递至后端Web应用。引入YARP的目的是提供公网静态IP,使Nginx容器及其挂载资源可安全部署于无公网IP的虚拟网络中。
该Web应用是基于.NET 4的传统WebForms应用,集成了ASP.NET Identity。除直接访问需授权页面的场景外,其余功能均正常:正常流程应为跳转至登录页,验证后返回原受限页面,但实际访问https://targethost.com/restrictedpage时,被重定向至https://nginxhost.com/login.aspx?returnUrl=/restrictedpage,而非预期的https://targethost.com/login.aspx?returnUrl=/restrictedpage。若先访问https://targethost.com/login.aspx完成登录,则可正常访问受限页面。
相关配置
YARP路由配置
"AllowedHosts": "*", "ReverseProxy": { "Routes": { "route1": { "ClusterId": "cluster1", "Match": { "Path": "{**catch-all}", "Hosts": [ "targethost.com" ] }, } }, "Clusters": { "cluster1": { "Destinations": { "destination1": { "Address": "http://nginxproxy.com:80/" } } } } }
Nginx代理配置
server { listen 80 default_server; server_name nginxproxy.com; set $upstream https://webapp.com; set $always_redirect off; location / { ... proxy_set_header Host $host; proxy_set_header Proxy ""; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-REAL-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; proxy_pass_header Authorization; proxy_pass $upstream; set_real_ip_from 10.5.3.254; set_real_ip_from 127.0.0.1; real_ip_header X-REAL-IP; real_ip_recursive on;. }
Web应用身份认证配置
app.UseCookieAuthentication(New CookieAuthenticationOptions() With { .ExpireTimeSpan = TimeSpan.FromMinutes(5), .SlidingExpiration = True, .AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, .Provider = New CookieAuthenticationProvider() With { .OnValidateIdentity = SecurityStampValidator.OnValidateIdentity(Of ApplicationUserManager, ApplicationUser)( validateInterval:=TimeSpan.FromMinutes(30), regenerateIdentity:=Function(manager, user) user.GenerateUserIdentityAsync(manager))}, .LoginPath = New PathString("/Account/Login")})
更新补充:OWIN中间件配置
Public Sub Configuration(app As IAppBuilder) Dim c = New CookieAuthenticationOptions c.AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie c.LoginPath = New PathString("/account/login") app.UseCookieAuthentication(c)
根据文档说明:LoginPath属性用于处理ChallengeAsync时的重定向目标,当前URL会以ReturnUrlParameter指定的查询参数附加至LoginPath,登录成功后会据此跳转回原URL。
核心问题是后端Web应用生成重定向URL时,使用了Nginx传递的Host头值(nginxproxy.com),而非用户实际访问的公网域名targethost.com:
- Nginx配置中
proxy_set_header Host $host;的$host变量会取Nginx自身的server_name值(即nginxproxy.com),导致后端Web应用误以为当前请求的主机是nginxproxy.com,生成登录跳转URL时就用了这个域名。 - .NET 4的ASP.NET Identity在处理未授权请求的重定向时,会基于当前请求的
Host头拼接完整的登录URL,未正确识别反向代理传递的原始请求域名。
方案1:修改Nginx配置,传递原始请求Host头
将Nginx配置中的proxy_set_header Host $host;替换为以下两种方式之一:
- 方式A:保留客户端原始Host头
proxy_set_header Host $http_host; - 方式B:固定为公网目标域名(仅适用于单一域名场景)
proxy_set_header Host targethost.com;
修改后的完整Nginx location片段:
location / { ... proxy_set_header Host $http_host; # 或者使用固定域名:proxy_set_header Host targethost.com; proxy_set_header Proxy ""; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-REAL-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; proxy_pass_header Authorization; proxy_pass $upstream; set_real_ip_from 10.5.3.254; set_real_ip_from 127.0.0.1; real_ip_header X-REAL-IP; real_ip_recursive on;. }
说明:$http_host会保留客户端请求时的原始Host头(即targethost.com),后端Web应用就能基于正确的域名生成登录跳转URL。
方案2:修改Web应用代码,拦截并重写重定向URL
若无法修改Nginx配置,可通过OWIN中间件拦截默认的重定向逻辑,手动替换域名:
Public Sub Configuration(app As IAppBuilder) Dim c = New CookieAuthenticationOptions c.AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie c.LoginPath = New PathString("/account/login") ' 拦截重定向逻辑,替换域名 c.Provider = New CookieAuthenticationProvider() With { .ApplyRedirect = Function(context) Dim redirectUrl = context.RedirectUri ' 将错误域名替换为公网目标域名 redirectUrl = redirectUrl.Replace("https://nginxproxy.com", "https://targethost.com") context.Response.Redirect(redirectUrl) End Function } app.UseCookieAuthentication(c) End Sub
说明:通过ApplyRedirect方法覆盖默认重定向行为,将生成的URL中的nginxproxy.com替换为targethost.com,确保跳转目标正确。
额外优化:配置Forwarded Headers
为确保Web应用正确识别原始请求的协议和客户端信息,可添加OWIN的UseForwardedHeaders中间件:
app.UseForwardedHeaders(New ForwardedHeadersOptions() With { .ForwardedHeaders = ForwardedHeaders.XForwardedFor Or ForwardedHeaders.XForwardedProto })
说明:该配置让应用信任反向代理传递的X-Forwarded-*头,有助于生成正确的HTTPS URL及获取真实客户端IP。
内容的提问来源于stack exchange,提问作者ibeme99

