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

Jas*_*son 139 asp.net forms-authentication

对此我砸了太久了.如何防止用户在使用FormsAuthentication.SignOut注销后浏览网站的页面?我希望这样做:

FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();
Run Code Online (Sandbox Code Playgroud)

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

Igo*_*mić 202

用户仍然可以浏览您的网站,因为在您拨打电话时不会清除Cookie,FormsAuthentication.SignOut()并且每次新请求都会对其进行身份验证.在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();
Run Code Online (Sandbox Code Playgroud)

HttpCookieSystem.Web命名空间中.MSDN参考.

  • 这适合我.但是值得注意的是,如果登录时在FormsAuthentication cookie上设置了Domain属性,则在注销时将cookie设置为exping时也需要设置 (16认同)
  • 另外不要忘记**cookie1.HttpOnly = true;** (7认同)
  • @RandyH.使用新的空cookie覆盖现有的FormsAuthentication cookie可确保即使客户端收回系统时钟,他们仍然无法从cookie中检索任何用户数据. (7认同)
  • 有人可以将所有这些评论结合到答案中吗? (7认同)
  • 这对我来说似乎是一个更好的解决方案:**Response.Cookies [FormsAuthentication.FormsCookieName] .Expires = DateTime.Now.AddDays(-1);** (6认同)
  • 别忘了!cookie1.Path = FormsAuthentication.FormsCookiePath; (5认同)
  • 如果您需要这样做,那么您有一些配置问题,因为`FormsAuthentication.SignOut()`执行此操作,除非您的身份验证配置不正确.但是,如果你想重置cookie的过期日期,至少要做正确的事.`HttpContext.Current.Request.Cookies.AllKeys.ToList().ForEach(s => HttpContext.Current.Request.Cookies [s] .Expires = DateTime.Now.AddDays(-1))`将迭代所有的cookie并且将他们的过期日期重置,以便在您注销时不会遗漏任何内容. (5认同)
  • 自上述回复写完以来已经有5年了.以上代码是否仍适用于visual studio 2013?你能把它粘贴到logout_button_Click事件中吗?谢谢. (3认同)
  • 什么域名属性? (2认同)
  • 正如我所注意到的那样,如果为.ASPXAUTH设置了Path,则FormsAuthentication.FormsCookiePath将不会选择它.因此,您需要使用保存在某处的变量设置cookie1.Path. (2认同)
  • 根据它出现的位置,可能需要在Response.End()之后跟随FormsAuthentication.RedirectToLoginPage(). (2认同)
  • Session.Abandon()确实中止当前会话但不清除会话标识符cookie.通过设计,可以重用会话标识符以在下一个请求上开始新会话.可以使用regenerateExpiredSessionId配置参数禁用此行为. (2认同)

jwa*_*rjr 20

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

<authentication mode="Forms">
  <forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
  <deny users="?" />
</authorization>
Run Code Online (Sandbox Code Playgroud)


jus*_*n23 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 );
    
    Run Code Online (Sandbox Code Playgroud)

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" ); 
    }
    
    Run Code Online (Sandbox Code Playgroud)


Phi*_*den 12

这里的关键是你说"如果我直接输入一个URL ......".

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

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Run Code Online (Sandbox Code Playgroud)

您可能还想致电:

Response.Cache.SetNoStore();
Run Code Online (Sandbox Code Playgroud)


Gle*_*tle 11

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

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

FormsAuthentication.SignOut()被调用时,系统会告诉乔失去的关键.通常,这是有效的,因为乔不再拥有钥匙,他无法进入.

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

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

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

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

  • + 1,我认为这称为'Cookie重播攻击'.有一篇关于FormsAuthentication.SignOut的限制的文章:http://support.microsoft.com/kb/900111 (7认同)
  • 对于任何想要点击上面链接的人来说,它已经死了。您可以尝试使用 WaybackMachine 在此处获取此页面的副本,但它会立即尝试重定向用户。http://web.archive.org/web/20171128133421/https://support.microsoft.com/en-us/help/900111/the-formsauthentication-signout-method-does-not-prevent-cookie-reply-一种 (3认同)

Kor*_*yem 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());
    }
Run Code Online (Sandbox Code Playgroud)


Kho*_*esh 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>
Run Code Online (Sandbox Code Playgroud)


see*_*uit 5

这个答案在技术上与 Khosro.Pakmanesh 相同。我发布它是为了澄清他的答案与该线程上的其他答案有何不同,以及它可以在哪些用例中使用。

一般来说要清除用户会话,做

HttpContext.Session.Abandon();
FormsAuthentication.SignOut();
Run Code Online (Sandbox Code Playgroud)

将有效地注销用户。但是,如果在同一个请求中您需要检查Request.isAuthenticated(例如,可能经常发生在授权过滤器中),那么您会发现

Request.isAuthenticated == true
Run Code Online (Sandbox Code Playgroud)

即使 _after 你做了HttpContext.Session.Abandon()FormsAuthentication.SignOut()

唯一有效的就是做

AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
Run Code Online (Sandbox Code Playgroud)

这有效地设置Request.isAuthenticated = false.