我们有一个需要登录的内部 ASP.NET MVC 应用程序。登录效果很好,并且符合预期。我们的会话到期时间为 5 分钟。在那段时间坐在一个页面上之后,用户已经失去了会话。如果他们尝试刷新当前页面或浏览到另一个页面,他们将获得一个登录页面。
我的问题是(重新登录后)在哪里告诉 MVC 重定向到他们的(刷新/浏览)尝试而不是总是获取 HOME 控制器页面?
我们有一个需要登录的内部 ASP.NET MVC 应用程序。登录效果很好,并且符合预期。我们的会话到期时间为 5 分钟。在那段时间坐在一个页面上之后,用户已经失去了会话。如果他们尝试刷新当前页面或浏览到另一个页面,他们将获得一个登录页面。
我的问题是(重新登录后)在哪里告诉 MVC 重定向到他们的(刷新/浏览)尝试而不是总是获取 HOME 控制器页面?
通常这应该自动发生。当匿名用户访问受保护的资源时(他是匿名的,因为他的会话已过期),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
最初请求的受保护资源作为查询字符串参数传递给配置的登录页面。因此,您可以在成功验证后将用户重定向到此页面。
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
,如辅助方法中所示)。
您的应用程序是否在维护此事件链?如果不是,那么这一系列事件在哪里中断?按照惯例,您应该:
returnUrl
从会话到期重定向接收。returnUrl
在登录表单中。returnUrl
成功登录后将用户重定向到。当您创建新的 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
,如果用户正在提交表单,它将不起作用。