Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ASP.NET窗体身份验证超时_Asp.net_Timeout_Forms Authentication - Fatal编程技术网

ASP.NET窗体身份验证超时

ASP.NET窗体身份验证超时,asp.net,timeout,forms-authentication,Asp.net,Timeout,Forms Authentication,这可能是一个非常简单的问题,但经过几个小时的努力,我仍然不知道这在ASP.NET4.0上是如何工作的 我正在使用表单身份验证。我有一个登录页面,上面有一个登录控件 这是用户登录时我需要的: A-用户应保持日志记录,直到用户对超时设置不做任何操作。如果重新加载页面,则超时必须重新开始倒计时 B-如果他们点击“记住我”复选框,他们应该保持连接,直到他们注销,无论他们是否关闭浏览器或重新启动计算机 我的问题是,当他们登录时,我在我的计算机上看不到任何cookie: 饼干在哪里?是内存cookie吗 如

这可能是一个非常简单的问题,但经过几个小时的努力,我仍然不知道这在ASP.NET4.0上是如何工作的

我正在使用表单身份验证。我有一个登录页面,上面有一个登录控件

这是用户登录时我需要的:

A-用户应保持日志记录,直到用户对超时设置不做任何操作。如果重新加载页面,则超时必须重新开始倒计时

B-如果他们点击“记住我”复选框,他们应该保持连接,直到他们注销,无论他们是否关闭浏览器或重新启动计算机

我的问题是,当他们登录时,我在我的计算机上看不到任何cookie:

  • 饼干在哪里?是内存cookie吗
  • 如果会话过期会发生什么?我想记录它们,除非超时完成
  • 如果应用程序池被回收,会发生什么
  • 另外,我还有一个问题:当他们点击“记住我”复选框(案例B)时,我希望他们在点击注销按钮之前登录。这一次我确实看到了一个cookie,但看起来它们只在超时时保持连接…那么记住我和不记住我之间的区别是什么

    我想将身份验证和会话完全分开。如果不是很糟糕,我希望通过cookies控制身份验证


    感谢您的帮助-。

    对于A您需要将会话超时变量设置为您希望用户登录多长时间

    对于部分B,我建议将该值存储在会话变量(或cookie,但不在服务器上)中,并在global.asax文件的session_End事件中检查该值。如果已设置,则续订会话


    当浏览器关闭时不会触发会话结束事件,当服务器在特定时间段(默认为20分钟)内未收到用户的请求时会触发会话结束事件

    处理非永久性滑动过期票据

    表单身份验证对票据使用内存中的cookie,除非将其持久化(例如,
    FormsAuthentication.SetAuthCookie(username,true)
    将使其持久化)。默认情况下,票据使用滑动到期。每次处理请求时,都会发送带有新过期日期的票据。一旦该日期过期,cookie和票据都将无效,用户将被重定向到登录页面

    表单身份验证没有用于重定向已呈现页面的内置处理,这些页面的放置时间超过超时时间。您需要自己添加这个。在最简单的级别上,您需要使用JavaScript启动一个带有文档加载的计时器

    <script type="text/javascript">
      var redirectTimeout = <%FormsAuthentication.Timeout.TotalMilliseconds%>
      var redirectTimeoutHandle = setTimeout(function() { window.location.href = '<%FormsAuthentication.LoginUrl%>'; }, redirectTimeout);
    </script>
    
    通过简单地发送AJAX请求,客户端超时和票据(以cookie的形式)都将被更新,您的用户应该不会有问题

    但是,如果用户活动没有导致更新FormsAuth票证,则用户在下次请求新页面时(通过导航或通过AJAX)将显示为注销。在这种情况下,当用户活动通过AJAX调用(例如,自定义处理程序、MVC操作等)发生时,您需要“ping”您的web应用程序,以使FormsAuth票证保持最新。请注意,在ping服务器以保持最新状态时,您需要小心,因为您不希望在服务器上充斥着请求,例如移动光标或单击对象。除了初始页面加载和AJAX请求之外,上面的init脚本还添加了一个新功能,它将
    resetRedirect
    添加到对文档的鼠标单击中

    $(function() {
       $(document).on('click', function() {
          $.ajax({url: '/ping.ashx', cache: false, type: 'GET' }); // because of the $.ajaxSetup above, this call should result in the FormsAuth ticket being updated, as well as the client redirect handle.
       });
    });
    
    处理“永久”票证

    您需要将票据作为持久cookie发送到客户端,并具有任意长的超时时间。您应该能够保持客户端代码和web.config不变,但在登录逻辑中分别处理用户对永久票证的偏好。在这里,您需要修改票据。下面是登录页面中执行此操作的逻辑:

    // assumes we have already successfully authenticated
    
    if (rememberMe)
    {
        var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddYears(50), true,
                                                   string.Empty, FormsAuthentication.FormsCookiePath);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
                         {
                             Domain = FormsAuthentication.CookieDomain,
                             Expires = DateTime.Now.AddYears(50),
                             HttpOnly = true,
                             Secure = FormsAuthentication.RequireSSL,
                             Path = FormsAuthentication.FormsCookiePath
                         };
        Response.Cookies.Add(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, true));
    }
    else
    {
        FormsAuthentication.RedirectFromLoginPage(userName, false);
    }
    
    奖励:在票证中存储角色

    您询问是否可以在ticket/cookie中存储角色,这样就不必再次查找它们。是的,这是可能的,但有一些考虑因素

  • 您应该限制放入票据中的数据量,因为cookie只能如此之大
  • 您应该考虑是否应该在客户端缓存角色。<李> 详细说明#2:

    您不应该隐式信任从用户处收到的声明。例如,如果一个用户登录并且是管理员,并选中“记住我”,从而收到一张持久的长期票据,那么他们将永远是管理员(或者直到cookie过期或被擦除)。如果有人将他们从数据库中的该角色中删除,应用程序仍会认为他们是管理员(如果他们有旧票证)。因此,您最好每次都获取用户的角色,但将角色缓存在应用程序实例中一段时间以最小化数据库工作

    从技术上讲,这也是门票本身的问题。同样,你不应该仅仅因为他们有一张有效的票证就相信这个帐户仍然有效。您可以使用与角色类似的逻辑:通过查询您的实际数据库,检查票证引用的用户是否仍然存在并且有效(它没有被锁定、禁用或删除),只需将db结果缓存一段时间以提高性能。这就是我在应用程序中所做的,其中票据被视为身份声明(类似地,用户名/密码是另一种声明类型)。下面是global.asax.cs(或HTTP模块)中的简化逻辑:

    当然,您可能决定不关心这些,只想信任票证,并将角色存储在票证中。首先,我们从上面更新您的登录逻辑:

    // assumes we have already successfully authenticated
    
    if (rememberMe)
    {
        var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddYears(50), true, GetUserRolesString(), FormsAuthentication.FormsCookiePath);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
                         {
                             Domain = FormsAuthentication.CookieDomain,
                             Expires = DateTime.Now.AddYears(50),
                             HttpOnly = true,
                             Secure = FormsAuthentication.RequireSSL,
                             Path = FormsAuthentication.FormsCookiePath
                         };
        Response.Cookies.Add(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, true));
    }
    else
    {
        var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout), false, GetUserRolesString(), FormsAuthentication.FormsCookieName);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
           {
              Domain = FormsAuthentication.CookieDomain,
              HttpOnly = true,
              Secure = FormsAuthentication.RequireSSL,
              Path = FormsAuthentication.FormsCookiePath
           };
        Response.Cookies.Add(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, false));
    }
    
    添加方法:

       private string GetUserRolesString(string userName)
       {
            // TODO: get roles from db and concatenate into string
       }
    
    更新您的global.asax.cs以取消角色限制
    // assumes we have already successfully authenticated
    
    if (rememberMe)
    {
        var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddYears(50), true, GetUserRolesString(), FormsAuthentication.FormsCookiePath);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
                         {
                             Domain = FormsAuthentication.CookieDomain,
                             Expires = DateTime.Now.AddYears(50),
                             HttpOnly = true,
                             Secure = FormsAuthentication.RequireSSL,
                             Path = FormsAuthentication.FormsCookiePath
                         };
        Response.Cookies.Add(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, true));
    }
    else
    {
        var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout), false, GetUserRolesString(), FormsAuthentication.FormsCookieName);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
           {
              Domain = FormsAuthentication.CookieDomain,
              HttpOnly = true,
              Secure = FormsAuthentication.RequireSSL,
              Path = FormsAuthentication.FormsCookiePath
           };
        Response.Cookies.Add(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, false));
    }
    
       private string GetUserRolesString(string userName)
       {
            // TODO: get roles from db and concatenate into string
       }
    
    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
      var application = (HttpApplication)sender;
      var context = application.Context;  
    
      if (context.User != null && context.User.Identity.IsAuthenticated && context.User.Identity is FormsIdentity)
      {
          var roles = ((FormsIdentity)context.User.Identity).Ticket.Data.Split(",");
    
          context.User = new GenericPrincipal(context.User.Identity, roles);
      }
    }