SystemWeb Adapters认证因多重重定向导致URL过长失败
问题
在使用SystemWeb Adapters和YARP从.NET 4.8 ASP.NET增量迁移至ASP.NET Core 8.0时,遇到认证循环重定向问题:未登录状态下用移动端访问首页,ReturnUrl被递归嵌套添加到请求URL中,导致URL超长(示例URL已省略重复部分)。
ASP.NET Core端代码
using WebCore; using Yarp.ReverseProxy.Forwarder; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddSystemWebAdapters() .AddJsonSessionSerializer(options => { // <snip> }) .AddRemoteAppClient( options => { options.RemoteAppUrl = new(builder.Configuration["ProxyTo"]); options.ApiKey = builder.Configuration["ProxyApiKey"]; }) .AddAuthenticationClient(isDefaultScheme: true) .AddSessionClient(); builder.Services.AddHttpForwarder(); builder.Services.AddDetection(); builder.Services.AddWebOptimizer(//<snip>); // <snip> var app = builder.Build(); var forwarderRequestConfig = builder.Configuration.GetSection("ForwarderRequestConfig") .Get<ForwarderRequestConfig>(); if (!app.Environment.IsDevelopment()) { app.UseHsts(); } app.UseCors(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseSystemWebAdapters(); app.MapForwarder("/{**catch-all}", app.Configuration["ProxyTo"], forwarderRequestConfig, new ForwardOriginalUrlTransformer()) .Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue); app.MapDefaultControllerRoute() .RequireSystemWebAdapterSession(); app.Run();
ASP.NET端AccountsController的Login方法
[Mobility] public ActionResult Login(string returnUrl = "", string mode = "") { SecurityService.Logout(); if (returnUrl.Contains("/account/login")) return RedirectToAction("login", "account", new { mode = "login" }); var model = new { Mode = mode, RedirectUrl = returnUrl, ValidationLiterals = AccountFacade.ValidationLiterals() }; return View(model.ToJson()); }
Mobility属性代码
public override void OnActionExecuting(ActionExecutingContext filterContext) { // Determine if we've processed their preference already via the UI site-switching links var useMobileValue = HttpContext.Current.Session["UseMobile"]; bool useMobile; // <snip> if (useMobile) { var url = "/mobile"; if (!Global.Authenticated) url += "/login"; filterContext.Result = new RedirectResult(url); } }
当前疑问:多重重定向是否会影响认证流程?有无可行解决办法?若将首页和Accounts控制器迁移至ASP.NET Core,该如何设置登录路径?
解决方案
问题根源
未登录移动端访问首页时,Mobility属性重定向到/mobile/login,该请求被YARP转发至旧ASP.NET应用;旧应用的Login方法检测到ReturnUrl包含/account/login会再次重定向,同时SystemWeb Adapters的认证客户端自动添加/systemweb-adapters/authenticate和original-url参数,形成循环重定向,导致ReturnUrl不断嵌套。
多重重定向会触发浏览器URL长度限制,增加服务器负载,直接中断正常认证流程,必须打破循环才能解决。
临时修复(不迁移控制器)
- 调整Mobility属性重定向逻辑:直接重定向到移动端登录页,避免携带可能引发循环的ReturnUrl
public override void OnActionExecuting(ActionExecutingContext filterContext) { var useMobileValue = HttpContext.Current.Session["UseMobile"]; bool useMobile; // <snip> if (useMobile) { var url = "/mobile/login"; // 直接重定向,不携带当前请求的returnUrl filterContext.Result = new RedirectResult(url); } }
- 修改旧Login方法的循环判断逻辑:精准识别循环路径,直接返回视图而非重定向
[Mobility] public ActionResult Login(string returnUrl = "", string mode = "") { SecurityService.Logout(); var loopPaths = new[] { "/account/login", "/mobile/login" }; if (!string.IsNullOrEmpty(returnUrl) && loopPaths.Any(p => returnUrl.Contains(p, StringComparison.OrdinalIgnoreCase))) { var model = new { Mode = mode, RedirectUrl = "", // 清空循环的ReturnUrl ValidationLiterals = AccountFacade.ValidationLiterals() }; return View(model.ToJson()); } var model = new { Mode = mode, RedirectUrl = returnUrl, ValidationLiterals = AccountFacade.ValidationLiterals() }; return View(model.ToJson()); }
迁移首页和Accounts控制器至ASP.NET Core的配置
- 配置认证与会话同步
// Program.cs 服务配置部分 builder.Services.AddAuthentication(SystemWebAdaptersAuthenticationDefaults.AuthenticationScheme) .AddSystemWebAdaptersAuthentication(); builder.Services.AddSystemWebAdapters() .AddJsonSessionSerializer(options => { // <snip> }) .AddRemoteAppClient(options => { options.RemoteAppUrl = new(builder.Configuration["ProxyTo"]); options.ApiKey = builder.Configuration["ProxyApiKey"]; }) .AddSessionClient();
- 调整中间件顺序
// Program.cs 管道配置部分 app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseSystemWebAdapters();
- 映射登录路由与授权策略
// 映射移动端登录路由 app.MapControllerRoute( name: "MobileLogin", pattern: "/mobile/login", defaults: new { controller = "Account", action = "MobileLogin" }); // 默认路由需授权 app.MapControllerRoute( name: "Default", pattern: "{controller=Home}/{action=Index}/{id?}") .RequireAuthorization();
- 编写ASP.NET Core端Account控制器
public class AccountController : Controller { public IActionResult Login(string returnUrl = "") { if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)) { ViewData["ReturnUrl"] = returnUrl; } return View(); } public IActionResult MobileLogin(string returnUrl = "") { // 复用Login视图,传递ReturnUrl ViewData["ReturnUrl"] = returnUrl; return View("Login"); } [HttpPost] public async Task<IActionResult> Login(LoginModel model, string returnUrl = "") { // 实现认证逻辑(可调用旧应用认证接口或通过SystemWeb Adapters同步会话) // 认证成功后重定向到原路径 if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)) { return Redirect(returnUrl); } return RedirectToAction("Index", "Home"); } }
内容的提问来源于stack exchange,提问作者user29953368
相关产品推荐
相关产品推荐

