3

我们有一个需要登录的内部 ASP.NET MVC 应用程序。登录效果很好,并且符合预期。我们的会话到期时间为 5 分钟。在那段时间坐在一个页面上之后,用户已经失去了会话。如果他们尝试刷新当前页面或浏览到另一个页面,他们将获得一个登录页面。

我的问题是(重新登录后)在哪里告诉 MVC 重定向到他们的(刷新/浏览)尝试而不是总是获取 HOME 控制器页面?

4

3 回答 3

3

通常这应该自动发生。当匿名用户访问受保护的资源时(他是匿名的,因为他的会话已过期),FormsAuthentication 模块会拦截此请求并通过附加指向受保护资源loginUrl的查询字符串参数重定向到您在 web.config 中注册的请求。ReturnUrl

因此,例如,如果您配置~/Account/LogOn为您的登录 url,并且匿名用户尝试访问~/Foo/Bar受保护的资源,他将被重定向到~/Account/LogOn?ReturnUrl=%2FFoo%2FBar.

然后他将看到一个登录页面,他将在其中输入他的凭据并将表单提交给控制器[HttpPost] LogOn上的操作。Account凭据将被验证,如果有效,将生成一个新的表单身份验证 cookie,并将用户重定向到最初请求的受保护资源。

以下是 LogOn 操作中的相应代码:

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

请注意用户是如何在成功验证后重定向到默认值Home/Index或参数的。returnUrl

当然,我在这里讲述的所有这些故事对于 Visual Studio 创建的默认 ASP.NET MVC 模板都是正确的。如果出于某种原因您修改了此模板,这可能会解释您所观察到的行为。

无论如何,从我的回答中要记住的是,如果您使用表单身份验证,该模块会将ReturnUrl最初请求的受保护资源作为查询字符串参数传递给配置的登录页面。因此,您可以在成功验证后将用户重定向到此页面。

于 2013-10-22T13:22:09.513 回答
2

AccountController通常,这在 ASP.NET MVC 应用程序中开箱即用。看一下默认Login操作:

[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    ViewBag.ReturnUrl = returnUrl;
    return View();
}

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
    {
        return RedirectToLocal(returnUrl);
    }

    // If we got this far, something failed, redisplay form
    ModelState.AddModelError("", "The user name or password provided is incorrect.");
    return View(model);
}

// later...
private ActionResult RedirectToLocal(string returnUrl)
{
    if (Url.IsLocalUrl(returnUrl))
        return Redirect(returnUrl);
    return RedirectToAction("Index", "Home");
}

当会话到期并且用户被重定向到登录页面时,系统应该returnUrl为该重定向提供一个参数。如果它不在您的应用程序中,那么在这种情况下,您的应用程序与默认设置有什么不同?

请注意第一个Login操作(在用户被重定向到登录页面后仅呈现登录页面)如何将该值包含在ViewBag. 此页面的默认视图将值添加到form元素,因此它将包含在登录 POST 请求中。第二个Login操作接收该请求,然后将用户定向到提供的 URL(或默认的/Index/Home,如辅助方法中所示)。

您的应用程序是否在维护此事件链?如果不是,那么这一系列事件在哪里中断?按照惯例,您应该:

  1. returnUrl从会话到期重定向接收。
  2. 包括returnUrl在登录表单中。
  3. returnUrl成功登录后将用户重定向到。
于 2013-10-22T13:23:45.183 回答
2

当您创建新的 ASP.Net MVC 项目时,此功能开箱即用。

简而言之,请求的 URL 作为参数发送到 MVC 框架的Index操作AccountController,然后成为登录页面 URL 的参数:

[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
  ViewBag.ReturnUrl = returnUrl;

  return View();
}

当用户发布他的凭据并且登录成功时,returnUrl用于将用户重定向到最初请求的页面:

[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginModel model, string returnUrl)
{
  if (ModelState.IsValid && Membership.ValidateUser(model.UserName, model.Password))
  {

    return RedirectToLocal(returnUrl);
  }

  // If we got this far, something failed, redisplay form
  ModelState.AddModelError("LogInIncorrectError", Resources.LogInIncorrectError);

  return View(model);
}

private ActionResult RedirectToLocal(string returnUrl)
{
  if (Url.IsLocalUrl(returnUrl))
  {
    return Redirect(returnUrl);
  }

  return RedirectToAction("Index", "Home");
}

我建议你创建一个新项目,看看它的行为如何......

请注意,这仅适用于HttpGet,如果用户正在提交表单,它将不起作用。

于 2013-10-22T13:22:55.400 回答