【问题标题】:MVC session expires - continue where leftMVC 会话过期 - 从剩下的地方继续
【发布时间】:2013-10-31 09:08:42
【问题描述】:

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

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

【问题讨论】:

    标签: asp.net asp.net-mvc session


    【解决方案1】:

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

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

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

    以下是登录操作的相应代码:

    [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/IndexreturnUrl 参数的。

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

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

    【讨论】:

      【解决方案2】:

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

      简而言之,请求的URL被MVC框架作为参数发送到AccountControllerIndex动作,然后成为登录页面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,如果用户正在提交表单,它将不起作用。

      【讨论】:

        【解决方案3】:

        这通常在 ASP.NET MVC 应用程序中使用 AccountController 开箱即用。看看默认的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

        【讨论】:

          猜你喜欢
          • 2019-10-27
          • 2019-06-14
          • 2015-01-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-31
          • 2013-08-16
          相关资源
          最近更新 更多