代码之家  ›  专栏  ›  技术社区  ›  Jason

FormsAuthentication.Signout()不注销用户

  •  138
  • Jason  · 技术社区  · 16 年前

    我的头撞在这上面太久了。如何阻止用户在使用FormsAuthentication.Signout注销后浏览网站页面?我希望这样做:

    FormsAuthentication.SignOut();
    Session.Abandon();
    FormsAuthentication.RedirectToLoginPage();
    

    但事实并非如此。如果我直接输入一个URL,我仍然可以浏览网页。我有一段时间没用过你自己的安全系统了,所以我忘了为什么这不管用。

    23 回复  |  直到 8 年前
        1
  •  197
  •   dana    8 年前

    用户仍然可以浏览您的网站,因为您呼叫时未清除cookie FormsAuthentication.SignOut() 每一个新的请求都会验证它们。在微软文档中,有人说cookie会被清除,但他们不会,bug? 它和 Session.Abandon() 曲奇还在那里。

    您应该将代码更改为:

    FormsAuthentication.SignOut();
    Session.Abandon();
    
    // clear authentication cookie
    HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
    cookie1.Expires = DateTime.Now.AddYears(-1);
    Response.Cookies.Add(cookie1);
    
    // clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
    SessionStateSection sessionStateSection = (SessionStateSection)WebConfigurationManager.GetSection("system.web/sessionState");
    HttpCookie cookie2 = new HttpCookie(sessionStateSection.CookieName, "");
    cookie2.Expires = DateTime.Now.AddYears(-1);
    Response.Cookies.Add(cookie2);
    
    FormsAuthentication.RedirectToLoginPage();
    

    HttpCookie 是在 System.Web 命名空间。 MSDN Reference .

        2
  •  21
  •   jwalkerjr    16 年前

    在我看来,您没有在中正确设置web.config授权部分。请参见下面的示例。

    <authentication mode="Forms">
      <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
    </authentication>
    <authorization>
      <deny users="?" />
    </authorization>
    
        3
  •  18
  •   justdan23    13 年前

    X64igor和Phil Haselden使用上述两个帖子解决了这一问题:

    1。X64igor给出了注销的示例:

    • 你首先需要 清除身份验证cookie和会话cookie 通过在注销响应中返回空cookie。

      public ActionResult LogOff()
      {
          FormsAuthentication.SignOut();
          Session.Clear();  // This may not be needed -- but can't hurt
          Session.Abandon();
      
          // Clear authentication cookie
          HttpCookie rFormsCookie = new HttpCookie( FormsAuthentication.FormsCookieName, "" );
          rFormsCookie.Expires = DateTime.Now.AddYears( -1 );
          Response.Cookies.Add( rFormsCookie );
      
          // Clear session cookie 
          HttpCookie rSessionCookie = new HttpCookie( "ASP.NET_SessionId", "" );
          rSessionCookie.Expires = DateTime.Now.AddYears( -1 );
          Response.Cookies.Add( rSessionCookie );
      

    2。Phil Haselden给出了上述关于如何防止注销后缓存的示例:

    • 你需要 通过响应使客户端的缓存失效 .

          // Invalidate the Cache on the Client Side
          Response.Cache.SetCacheability( HttpCacheability.NoCache );
          Response.Cache.SetNoStore();
      
          // Redirect to the Home Page (that should be intercepted and redirected to the Login Page first)
          return RedirectToAction( "Index", "Home" ); 
      }
      
        4
  •  12
  •   Phil Haselden    15 年前

    这里的关键是你说“如果我直接输入一个URL…”。

    默认情况下,在“窗体身份验证”下,浏览器为用户缓存页面。因此,直接从浏览器地址框下拉列表中选择一个URL,或者输入它,可能会从浏览器的缓存中获取页面,并且永远不会返回到服务器来检查身份验证/授权。解决方法是防止客户端缓存在每个页面的页面加载事件中,或在基本页面的onload()中:

    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    

    您也可以拨打:

    Response.Cache.SetNoStore();
    
        5
  •  10
  •   Glen Little    14 年前

    我也曾为此挣扎过。

    这是一个类比,似乎是在发生什么…一个新的访问者,乔,来到这个网站,并通过登录页面使用FormsAuthentication登录。ASP.NET为Joe生成一个新的标识,并给他一个cookie。那饼干就像房子的钥匙,只要乔拿着钥匙回来,他就能打开锁。每个访问者都会得到一把新钥匙和一把新锁。

    什么时候? FormsAuthentication.SignOut() 被调用时,系统会通知Joe丢失密钥。通常情况下,这是可行的,因为乔已经没有钥匙了,他不能进去。

    但是,如果乔回来了, 把钥匙丢了,他被放回去了!

    据我所知,无法告诉ASP.NET更改门上的锁!

    我能接受的方法是在会话变量中记住joe的名字。当他注销时,我放弃了会话,所以我不再知道他的名字了。稍后,为了检查是否允许他进入,我只需将他的身份.name与当前会话的内容进行比较,如果不匹配,他就不是有效的访问者。

    简而言之,对于一个网站,不要依赖 User.Identity.IsAuthenticated 不检查会话变量!

        6
  •  6
  •   Korayem Praphul Katlana    13 年前

    这对我有用

    public virtual ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            foreach (var cookie in Request.Cookies.AllKeys)
            {
                Request.Cookies.Remove(cookie);
            }
            foreach (var cookie in Response.Cookies.AllKeys)
            {
                Response.Cookies.Remove(cookie);
            }
            return RedirectToAction(MVC.Home.Index());
        }
    
        7
  •  6
  •   Khosro.Pakmanesh    9 年前

    经过大量的搜索,我终于明白了这一点。希望能有所帮助。

    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut();
        HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
        return RedirectToAction("Index", "Home");
    }
    
    <li class="page-scroll">@Html.ActionLink("Log off", "LogOff", "Account")</li>
    
        8
  •  3
  •   Abram Simon    16 年前

    您发布的代码看起来应该正确地删除表单身份验证令牌,因此可能相关的文件夹/页面实际上没有受到保护。

    您确认在登录之前无法访问页面吗?

    你能发布你正在使用的web.config设置和登录代码吗?

        9
  •  3
  •   Wahid Shalaly    15 年前

    我一直在为我所有的页面编写一个基础类,我也遇到了同样的问题。 我有如下代码,但它不起作用。通过跟踪,控件将从RedirectToLoginPage()语句传递到下一行,而不进行重定向。

    if (_requiresAuthentication)
    {
        if (!User.Identity.IsAuthenticated)
            FormsAuthentication.RedirectToLoginPage();
    
        // check authorization for restricted pages only
        if (_isRestrictedPage) AuthorizePageAndButtons();
    }
    

    我发现有两种解决办法。 将FormsAuthentication.RedirectToLoginPage();修改为

    if (!User.Identity.IsAuthenticated)
        Response.Redirect(FormsAuthentication.LoginUrl);
    

    或者通过添加

    <authorization>
      <deny users="?" />
    </authorization>
    

    在第二种情况下,跟踪时,控件未到达请求的页。在到达断点之前,它已被立即重定向到登录URL。 因此,signout()方法不是问题所在,重定向方法就是问题所在。

    我希望这能帮助别人

    当做

        10
  •  3
  •   DonH    13 年前

    我在这里尝试了一些建议,当我能够使用浏览器后退按钮时,当我单击菜单选择时,该[ActionResult]的[authorize]令牌将我直接发送回登录屏幕。

    这是我的注销代码:

            FormsAuthentication.SignOut();
            Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
            Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
            HttpCookie cookie = HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (cookie != null)
            {
                cookie.Expires = DateTime.Now.AddDays(-1);
                Response.Cookies.Add(cookie);
            }
    

    虽然浏览器上的后退功能让我返回并显示了安全菜单(我仍在努力实现这一点),但我无法执行应用程序中的任何安全操作。

    希望这有帮助

        11
  •  3
  •   stoffen    11 年前

    我试过这条线索的大部分答案,没有运气。结果是:

    protected void btnLogout_Click(object sender, EventArgs e)
    {
        FormsAuthentication.Initialize();
        var fat = new FormsAuthenticationTicket(1, "", DateTime.Now, DateTime.Now.AddMinutes(-30), false, string.Empty, FormsAuthentication.FormsCookiePath);
        Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(fat)));
        FormsAuthentication.RedirectToLoginPage();
    }
    

    在这里找到: http://forums.asp.net/t/1306526.aspx/1

        12
  •  3
  •   seebiscuit    8 年前

    这个答案在技术上与khosro.pakmanesh相同。我发布它是为了澄清他的答案与这个线程上的其他答案的区别,以及在哪个用例中可以使用它。

    通常清除用户会话,执行

    HttpContext.Session.Abandon();
    FormsAuthentication.SignOut();
    

    将有效注销用户。 然而 ,如果在同一请求中需要检查 Request.isAuthenticated (例如,在授权过滤器中经常会发生这种情况),然后您会发现

    Request.isAuthenticated == true
    

    即使在你做了之后 HttpContext.Session.Abandon() FormsAuthentication.SignOut() .

    唯一有效的方法就是

    AuthenticationManager.SignOut();
    HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
    

    有效地设置 Request.isAuthenticated = false .

        13
  •  2
  •   stema Arun Mohan    13 年前

    当我设置 身份验证>表单>路径属性 在里面 Web.config . 解决了这个问题, FormsAuthentication.SignOut(); 再次移除了cookie。

        14
  •  1
  •   jorsh1    16 年前

    可能是您从一个子域(sub1.domain.com)登录,然后尝试从另一个子域(www.domain.com)注销。

        15
  •  1
  •   Peder Skou    15 年前

    我也遇到了同样的问题,其中signout()似乎无法正确删除票据。但只有在特定情况下,某些其他逻辑导致了重定向。删除第二个重定向(用错误消息替换它)后,问题就消失了。

    问题一定是页面在错误的时间重定向,因此不会触发身份验证。

        16
  •  1
  •   lostatredrock    13 年前

    我现在有一个类似的问题,我相信在我的情况下,问题和原来的海报是因为重定向。默认情况下,response.redirect会导致一个异常,该异常会立即冒泡,直到捕获到该异常并立即执行重定向。我猜想这会阻止修改后的cookie集合传递给客户端。如果修改代码以使用:

    Response.Redirect("url", false);
    

    这可以防止异常,并且似乎允许将cookie正确地发送回客户机。

        17
  •  1
  •   David Cain    11 年前

    只需在按“登录”时发送会话变量即可。 在欢迎页面上,首先在页面加载或init事件中检查该会话是否为空:

    if(Session["UserID"] == null || Session["UserID"] == "")
    {
        Response.Redirect("Login.aspx");
    }
    
        18
  •  1
  •   Aji    8 年前

    对我来说,下面的方法是有效的。我认为如果在“formsAuthentication.signout()”语句后有任何错误,那么singout将不起作用。

    public ActionResult SignOut()
        {
            if (Request.IsAuthenticated)
            {
                FormsAuthentication.SignOut();
    
                return Redirect("~/");
            }
            return View();
         }
    
        19
  •  0
  •   Stobor    16 年前

    你是否使用IE测试/观察这种行为?有可能IE正在从缓存中提供这些页面。众所周知,要让IE刷新它的缓存是非常困难的,因此在许多情况下,即使在注销之后,键入其中一个“安全”页面的URL也会显示以前缓存的内容。

    (即使您以不同的用户身份登录,我也看到过这种行为,IE在页面顶部显示了“欢迎”栏,其中显示了旧用户的用户名。现在,通常重新加载会更新它,但是如果它是持久的,它仍然可能是一个缓存问题。)

        20
  •  0
  •   James    13 年前

    做session.discarge()和销毁cookie非常有效。我使用的是MVC3,如果您转到受保护的页面、注销并浏览浏览器历史记录,就会出现问题。没什么大不了的,但还是有点烦人。

    不过,尝试浏览我的Web应用程序上的链接是正确的。

    将其设置为不进行浏览器缓存可能是可行的方法。

        21
  •  0
  •   anovo    9 年前

    对于MVC,这对我很有用:

            public ActionResult LogOff()
            {
                FormsAuthentication.SignOut();
                return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
            }
    
        22
  •  0
  •   RogerMKE    9 年前

    我想添加一些信息来帮助理解这个问题。表单身份验证允许将用户数据存储在cookie或URL的查询字符串中。网站支持的方法可以在web.config文件中配置。

    According to Microsoft :

    签出方法删除窗体身份验证票证信息 从cookie或url 如果支持的厨师是假的 .

    同时, they say :

    httpCookieMode值之一,指示 应用程序配置为无烹饪窗体身份验证。 这个 默认为usedeviceprofile .

    最后,关于使用的设备配置文件, they say :

    如果CookieMode属性设置为UseDeviceProfile,则 如果浏览器 当前请求同时支持cookie和使用cookie重定向 ; 否则,cookiessupported属性将返回false。

    将所有这些结合在一起,根据用户的浏览器,默认配置可能导致支持的cookies 这意味着签出方法不能从cookie中清除票据。这似乎有悖常理,我不知道为什么它是这样工作的——我希望注销在任何情况下都能实际注销用户。

    使注销本身生效的一种方法是在web.config文件中将cookie模式更改为“usecookies”(即需要cookie):

    <authentication mode="Forms">
      <forms loginUrl="~/Account/SignIn" cookieless="UseCookies"/>
    </authentication>
    

    根据我的测试,这样做会使签出自己的工作,而代价是你的网站现在需要cookies正常工作。

        23
  •  -1
  •   Stefan    11 年前

    注意WIF 拒绝 如果来自sts的wsignoutcleanup消息与来自IIS的应用程序名称不匹配,告诉浏览器清除cookie,我的意思是 区分大小写 . WIF用绿色OK检查进行响应,但会 向浏览器发送删除cookie的命令。

    因此,您需要注意URL的大小写敏感性。

    例如,ThinkConnectIdentity Server将访问的RPS的URL保存在一个cookie中,但它会使所有URL的大小写都变小。wif将接收小写的wsignoutcleanup消息,并将其与IIS中的应用程序名进行比较。如果不匹配,则不会删除cookie,但会向浏览器报告OK。因此,对于这个Identity Server,我需要在web.config中编写所有URL,在小写的情况下编写所有IIS中的应用程序名,以避免此类问题。

    如果您的应用程序不在STS的子域内,也不要忘记在浏览器中允许第三方cookie,否则即使WIF告诉他,浏览器也不会删除cookie。