FormsAuthentication.SignOut()不会将用户注销

时间:2009-01-05 04:48:42

标签: asp.net forms-authentication

我的头撞了这么长时间。如何防止用户在使用FormsAuthentication.SignOut注销后浏览网站的页面?我希望这样做:

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

但事实并非如此。如果我直接输入URL,我仍然可以浏览到该页面。我有一段时间没有使用自己的安全性,所以我忘记了为什么这不起作用。

23 个答案:

答案 0 :(得分:198)

用户仍然可以浏览您的网站,因为在您致电FormsAuthentication.SignOut()时不会清除Cookie,并且会在每次新请求时对其进行身份验证。在MS文档中说cookie将被清除,但它们没有,bug? 与Session.Abandon()完全相同,cookie仍在那里。

您应该将代码更改为:

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

答案 1 :(得分:20)

听起来像你没有正确设置你的web.config授权部分。请参阅下面的示例。

<authentication mode="Forms">
  <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
  <deny users="?" />
</authorization>

答案 2 :(得分:20)

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" ); 
    }
    

答案 3 :(得分:12)

这里的关键是你说“如果我直接输入网址......”。

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

Response.Cache.SetCacheability(HttpCacheability.NoCache);

您可能还想致电:

Response.Cache.SetNoStore();

答案 4 :(得分:11)

我之前也在努力解决这个问题。

以下是对似乎正在发生的事情的类比......新访问者Joe来到网站并使用FormsAuthentication通过登录页面登录。 ASP.NET为Joe生成一个新标识,并为他提供一个cookie。那个饼干就像是房子的钥匙,只要乔带着那把钥匙回来,他就可以打开锁。每个访问者都会获得一个新密钥和一个新锁。

当调用FormsAuthentication.SignOut()时,系统会告诉Joe丢失密钥。通常情况下,这是有效的,因为乔不再拥有钥匙,他无法进入。

但是,如果Joe回来了,并且确实丢失了密钥,那么他就会被让回来!

据我所知,没有办法告诉ASP.NET更改门锁!

我可以采用的方法是在Session变量中记住Joe的名字。当他退出时,我放弃了会议,所以我不再有他的名字了。稍后,为了检查他是否被允许,我只是将他的Identity.Name与当前会话的内容进行比较,如果它们不匹配,则他不是有效的访问者。

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

答案 5 :(得分:6)

经过大量搜索后,这对我有用。我希望它有所帮助。

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>

答案 6 :(得分:6)

这对我有用

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 :(得分:3)

此答案在技术上与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

答案 8 :(得分:3)

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

您是否确认在登录之前无法访问这些页面?

您可以发布您正在使用的web.config设置和登录代码吗?

答案 9 :(得分:3)

我在这个帖子中尝试了大多数答案,没有运气。结束了这个:

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

答案 10 :(得分:3)

我刚刚尝试了一些建议,当我能够使用浏览器后退按钮时,当我点击菜单选项时,[ActionResult]的[Authorize]令牌将我发送回登录屏幕。< / p>

这是我的退出代码:

        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)

我一直在为所有的Pages编写基类,我遇到了同样的问题。 我有类似下面的代码,它没有用。通过跟踪,控制从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);

或者通过添加

来修改web.config
<authorization>
  <deny users="?" />
</authorization>

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

我希望这可以帮助某人

此致

答案 12 :(得分:2)

当我设置身份验证&gt;时,这开始发生在我身上表格&gt; Web.config中的路径属性。删除它解决了问题,而简单的FormsAuthentication.SignOut();再次删除了Cookie。

答案 13 :(得分:1)

我现在遇到类似的问题,我相信我的案例以及原始海报的问题是因为重定向。默认情况下,Response.Redirect会导致异常,该异常会立即冒出,直到被捕获并立即执行重定向,我猜这是阻止修改后的cookie集合传递给客户端。如果您修改要使用的代码:

Response.Redirect("url", false);

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

答案 14 :(得分:1)

我遇到了同样的问题,SignOut()似乎无法正确删除故障单。但仅在特定情况下,其他一些逻辑导致重定向。在我删除了第二次重定向(替换为错误消息)之后,问题就消失了。

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

答案 15 :(得分:1)

按下登录时尝试发送会话变量。 在欢迎页面上,首先在页面加载或Init事件中检查该会话是否为空:

if(Session["UserID"] == null || Session["UserID"] == "")
{
    Response.Redirect("Login.aspx");
}

答案 16 :(得分:1)

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

答案 17 :(得分:1)

对我来说,以下方法有效。我想如果&#34; FormsAuthentication.SignOut()&#34;之后有任何错误。声明,SingOut没有工作。

public ActionResult SignOut()
    {
        if (Request.IsAuthenticated)
        {
            FormsAuthentication.SignOut();

            return Redirect("~/");
        }
        return View();
     }

答案 18 :(得分:0)

执行Session.abandon()并销毁cookie非常有用。我正在使用mvc3,如果您访问受保护的页面,注销并通过浏览器历史记录,则看起来会出现问题。没什么大不了的,但还是有点讨厌。

尝试通过我的网络应用上的链接以正确的方式工作。

将其设置为不进行浏览器缓存可能是最佳选择。

答案 19 :(得分:0)

对于MVC,这对我有用:

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
        }

答案 20 :(得分:0)

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

According to Microsoft

  

SignOut方法删除表单身份验证票证信息   来自Cookie或网址 ,如果CookiesSupported为false

与此同时,they say

  

其中一个HttpCookieMode值指示是否   应用程序配置为无cookie表单身份验证。的    默认为UseDeviceProfile

最后,关于UseDeviceProfile,they say

  

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

将所有内容拼凑在一起,具体取决于用户的浏览器,默认配置可能导致CookiesSupported true ,这意味着SignOut方法不会从cookie中清除票证。这似乎是违反直觉的,我不知道它为什么会这样 - 我希望SignOut在任何情况下实际签署用户。

使SignOut单独工作的一种方法是在web.config文件中将cookie模式更改为“UseCookies”(即需要cookie):

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

根据我的测试,这样做会使SignOut以您自己的网站为代价自行运行,现在要求Cookie正常运行。

答案 21 :(得分:0)

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

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

答案 22 :(得分:-1)

请注意,如果来自STS的wsignoutcleanup消息与来自IIS的应用程序名称的url不匹配,WIF 拒绝告诉浏览器清理Cookie,我的意思是案例敏感。 WIF以绿色OK检查响应,但发送命令删除浏览器的cookie。

因此,您需要注意网址的区分大小写。

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

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