You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Web API登录后重定向用户:如何保存初始路径实现跳转?

保存原访问路径并在登录后重定向的最佳实践

在ASP.NET MVC场景下,处理这种“登录后返回原请求页面”的需求,最成熟也最符合框架设计的方式是利用ReturnUrl参数传递原路径,既简单又能避免安全问题。结合你的CustomAuthorizeAttribute,我给你具体的实现方案:


第一步:在自定义授权特性中传递原路径

当用户未授权时,我们需要获取他原本请求的完整URL,编码后作为ReturnUrl参数附加到登录页的跳转地址上。修改你的CustomAuthorizeAttribute代码如下:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
        base.OnAuthorization(filterContext);
        
        // 检查是否未授权且尚未处理重定向
        if (filterContext.Result is HttpUnauthorizedResult)
        {
            // 获取原请求的完整路径(包括查询参数)
            var originalUrl = filterContext.HttpContext.Request.Url;
            if (originalUrl != null)
            {
                var returnUrl = $"{originalUrl.AbsolutePath}{originalUrl.Query}";
                // 对路径进行URL编码,避免特殊字符导致参数解析失败
                var encodedReturnUrl = HttpUtility.UrlEncode(returnUrl);
                // 重定向到登录页并带上ReturnUrl
                filterContext.Result = new RedirectResult($"~/Account/Login?ReturnUrl={encodedReturnUrl}");
            }
        }
    }
}

第二步:登录成功后验证并跳转回原路径

在你的登录Action中,需要读取ReturnUrl参数,必须先验证它是否是本地URL(防止开放重定向攻击),然后再重定向过去。示例代码:

[HttpGet]
public ActionResult Login(string returnUrl)
{
    // 把ReturnUrl传递给视图,方便表单提交时携带
    ViewBag.ReturnUrl = returnUrl;
    return View();
}

[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        // 这里替换成你的用户验证逻辑
        if (AuthenticateUser(model.Username, model.Password))
        {
            // 生成JWT令牌并保存(比如存在Cookie或响应头)
            var jwtToken = GenerateJwtToken(model.Username);
            Response.Cookies.Append("JwtToken", jwtToken, new CookieOptions { HttpOnly = true, Secure = true });
            
            // 验证ReturnUrl是否为本地合法路径,避免恶意跳转
            if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            // 如果没有合法的ReturnUrl,跳转到默认首页
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        ModelState.AddModelError("", "用户名或密码错误");
    }
    // 登录失败,返回登录页并保留ReturnUrl
    ViewBag.ReturnUrl = returnUrl;
    return View(model);
}

第三步:在登录视图中携带ReturnUrl

确保你的登录表单里包含ReturnUrl的隐藏字段,这样POST请求时能把参数传递给登录Action:

@model LoginViewModel

@using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
    @Html.Hidden("returnUrl", ViewBag.ReturnUrl)
    
    <!-- 其他用户名、密码输入框 -->
    <div>
        @Html.LabelFor(m => m.Username)
        @Html.TextBoxFor(m => m.Username)
    </div>
    <div>
        @Html.LabelFor(m => m.Password)
        @Html.PasswordFor(m => m.Password)
    </div>
    <button type="submit">登录</button>
}

为什么不推荐用Session存储?

虽然把原路径存在Session里也能实现,但对于JWT这种无状态认证的场景,URL参数的方式更契合设计理念——不需要依赖服务器端会话状态,而且更直观、易于调试。另外,Session可能会因为超时、分布式部署等问题导致丢失,而ReturnUrl参数则不存在这些问题。


内容的提问来源于stack exchange,提问作者Оля

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:36:37