【问题标题】:ReturnUrl Points to an ActionResultReturnUrl 指向 ActionResult
【发布时间】:2018-04-05 17:03:04
【问题描述】:

场景如下:

  • 从头开始一个 MVC 项目
  • 用 [Authorize] 属性装饰的测试控制器
  • 用户登录并定向到主页
  • 用户点击一个链接会重定向到TestControllerIndex方法
  • 用户等待 60 秒以使表单身份验证超时
  • 用户单击一个链接,该链接调用驻留在TestController 上的 ActionMethod
  • MVC 框架将用户重定向到登录页面并将 ActionMethod 名称附加到 URL,而不是附加 Index 操作方法

TestController

[Authorize]
public class TestController : Controller
{
    // GET: Test
    public ViewResult Index()
    {
        return View();
    }

    [ValidateInput(false)]
    public ActionResult ActionTest()
    {
        return new EmptyResult();
    }
}

HomeController

[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

AccountController

public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            try
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);

                if (Url.IsLocalUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                else
                    return RedirectToAction(controllerName: "Home", actionName: "Index");
            }
            catch
            {
                return View(model);
            }
        }
        return View(model);
    }
}

Login.chtml

@model TestLoginProject.Models.LoginViewModel

@{
    Layout = null;
}

<!DOCTYPE html>
<html lang="en">
<head>
  .....................
</head>

<body>
    <div class="container">
        @using (@Html.BeginForm("Login", "Account", new { returnUrl = Request.QueryString["ReturnUrl"] }, FormMethod.Post, new { @class = "form-signin" }))
        {
            @Html.AntiForgeryToken()
            ....................
            ....................
        }
    </div>
</body>
</html>

网络配置

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login" timeout="1" />
</authentication>

返回url的期望是

http://localhost:2441/Account/Login?ReturnUrl=%2fTest%2fIndex

相反,当前值为

http://localhost:2441/Account/Login?ReturnUrl=%2fTest%2fActionTest

注意事项

  • 当用户在超时后单击链接时,在重定向到登录页面之前没有命中任何测试操作
  • 在 VS2017 中从头开始一个 Empty MVC 项目时,所有路由都是默认提供的

【问题讨论】:

  • 分享您的路线和查看页面。还要在操作(或日志)中放置一个断点,以查看调用了哪个操作以及如果多个操作以什么顺序调用
  • @YishaiGalatzer,在表单身份验证超时后,我尝试再次登录,只命中了 SomePagePartialView 操作。
  • @YishaiGalatzer,该视图几乎只包含以下相关行:@Html.Action("SomePagePartialView")
  • URL 通常由路由生成。您尚未在问题中发布一条路线。
  • 要么你的路由表有问题(我怀疑,但你应该检查一下),或者你的登录将你发送到部分视图而不是视图(调试它)。最后,您的主视图通过 Action("SomePagePartialView") 将您发送到局部视图,为了 100% 确定,现在让该视图返回其他内容(与 PartialViewPage 相同)

标签: asp.net-mvc security authentication asp.net-mvc-routing forms-authentication


【解决方案1】:

这是你提到的正常行为!

MVC 框架将用户重定向到登录页面并附加 ActionMethod 名称到 URL,而不是附加 Index Action Method

非常感谢 MVC 安全管道。当您使用 forms 身份验证 并且用户未经过身份验证或授权时,ASP.NET 安全管道将重定向到登录页面并将returnUrl 作为参数传递等于重定向到的页面登录页面(这是需要授权的控制器操作,您可以通过单击链接调用)。

所以在这里你不能期望 index(当前加载的页面没有有效和持久的身份验证),随后 ActionMethod 调用安全管道和 returnurl 及时枚举。

注意这是因为控制器和视图之间的同步通信。

【讨论】:

  • 感谢您的洞察力。不幸的是,这种“正常行为”引入了不同类型的问题,因为该链接可能重定向到 PartialView 而不是 View;在这种情况下,如果用户再次登录,他/她将被定向到扭曲或剥离的 PartialView。您认为这个问题的最佳解决方案是什么?
  • @usefulBee,不清楚你真正想要什么。如果 URL 是由浏览器本身加载的,那么它应该是浏览器可以显示的完整 HTML 页面。如果对 URL 的请求是通过某些 AJAX 完成的 - 您有责任在您的 Javascript 中处理响应,并且您可以在那里重定向您想要的任何地方。我不确定您提到“重定向到 PartialView 而不是 View”是什么意思
  • @usefulBee 您可以根据需要在视图(剃须刀)或控制器端控制returnurl值以满足目的。
  • @AmirhosseinMehrvarzi,PartialView 我的意思是 returnUrl 指向 ActionResult 而不是 ViewResult。 ViewResult 预计将是一个完整的 html 页面,其中包含您提到的布局等。
  • @usefulBee 如果您深入了解其含义,您就会明白,当您使用PartialView 时,您也必须了解控制器方面。在这里您不能再次将视图状态传递给控制器​​。关注这个现实,你应该只通知控制器,你处理同步页面还是异步?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多