FormsAuthentication.SignOut()之后Page.User.Identity.IsAuthenticated仍然为真

65
我有一个页面,当你点击“注销”时它会重定向到 login.aspx 页面,该页面有一个 Page_Load 方法,调用了 FormsAuthentication.SignOut()
主页面在屏幕右上角显示“注销”链接,并在满足 Page.User.Identity.IsAuthenticatedtrue 的条件下显示。然而,在经过代码调试后,发现这个注销方法并没有自动将 IsAuthenticated 设置为 false,这非常令人烦恼,有什么想法吗?

我的理解是,你应该检查认证 cookie 的存在,而不是这个标志? - Sheen
1
我该怎么做呢?我认为在FormsAuthentication.SignOut()之后,cookie仍然存在。 - andrewm
可能是重复的问题 https://dev59.com/s3RC5IYBdhLWcg3wFdFx - BrokenGlass
2
请记住: 已认证 = “系统知道你是谁” 已授权 = “系统知道你被允许做什么”。 也就是说:注销 = “未被授权做任何事情”,但“系统仍然知道你是谁”。 - Kasper Jensen
7个回答

112

Page.User.Identity.IsAuthenticated的值来自于Page.User(显然),但遗憾的是Page.User是只读的,当您调用FormsAuthentication.SignOut()时没有更新。

幸运的是,Page.User从可以被修改的Context.User中获取其值:

// HttpContext.Current.User.Identity.IsAuthenticated == true;

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

// now HttpContext.Current.User.Identity.IsAuthenticated == false
// and Page.User.Identity.IsAuthenticated == false

当您注销当前用户并希望响应实际页面而不进行重定向时,此功能非常有用。您可以在同一页面请求中需要检查IsAuthenticated


稍有延迟的回答,但从记忆中我认为这与问题最终是如何解决的类似! - andrewm
14
稍微为你延迟一下,但我刚刚遇到了同样的问题,并找到了你的优秀问题,但没有得到恰当的答案。我希望它能对其他人有所帮助。 - Mart
2013年也帮助了我! :) - Mahmoud Moravej
9
在MVC4中使用完美,只需进行小改动:HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null); - Ferran Salguero
2
我也使用了HttpContext.Current.User = null; 如果你正在检查一个空的“User”,这很有用。 - Bern
请显示所使用的库的完整路径: System.Web.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new System.Security.Principal.GenericIdentity(string.Empty), null); - Spencer Sullivan

13

一个请求只会验证一次身份。一旦ASP.NET确定了用户是否已经通过验证,那么在该请求的剩余时间内,其身份状态将不会更改。

例如,当有人登录时。当您设置Forms身份验证cookie以指示他们已登录时,如果您在同一请求上检查它们是否已认证,它将返回false,但在下一个请求中,它将返回true。当您注销某个用户时,也是同样的情况。在该请求的持续时间内,他们仍然被验证,但在下一个请求中,他们将不再被验证。因此,如果用户单击链接以注销,则应先注销他们,然后重定向到登录页面。


6

我记得曾经遇到过类似的问题,我认为我通过在注销时使表单身份验证 cookie 过期来解决了这个问题:

FormsAuthentication.SignOut();
Response.Cookies[FormsAuthentication.FormsCookieName].Expires = DateTime.Now.AddYears(-1);

4

为什么在login.aspx中执行注销代码?

将此代码放入logout.aspx中:

FormsAuthentication.SignOut()
Session.Abandon()
FormsAuthentication.RedirectToLoginPage()
HttpContext.Current.ApplicationInstance.CompleteRequest()
return

IsAuthenticated属性在login.aspx页面将为false。 登录和注销代码现已分离:单一职责原则。


1
在你的login.aspx页面的Page_Load方法中:
if (!this.IsPostBack)
{
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
        FormsAuthentication.SignOut();
        Response.Redirect(Request.RawUrl);
    }
}

1
在我的一个应用程序中,当我使用凭据登录后,导航到应用程序中的不同表单,然后复制了我导航的表单网址,然后注销应用程序。在搜索选项卡中,我粘贴了网址,浏览器在未登录的情况下导航到我的应用程序中的特定表单。 在检查表单身份验证时,page.User.Identity.IsAuthenticated 被视为 true,即使我们已经注销。造成这种情况的原因是,在注销时清除会话时,我已添加了


Response.Cookies[FormsAuthentication.FormsCookieName].Expires = DateTime.Now.AddYears(-1);

使用这个方法之后,我再也不会遇到那个问题了,而且在没有登录的情况下导航到应用程序中的不同表单时,标志page.User.Identity.IsAuthenticated显示为false。

0

更新

我收到了许多人的评论,说我的答案对很多人都不起作用。我在2011年写下这个答案时,曾经非常费心地研究过。所以我非常确定它可以解决问题。

我开始研究这个6年前的问题,并且找到了这个解决方案,我相信这可能是删除cookie的正确方法,即通过重新创建带有过期日期的cookie来删除它们。


这对我有效

public virtual ActionResult LogOff()
    {
        FormsAuthentication.SignOut();
        foreach (var cookie in Response.Cookies.AllKeys)
        {
            Response.Cookies.Remove(cookie);
        }
        return RedirectToAction(MVC.Home.Index());
    }

1
在响应中删除Cookie不会导致其被删除。Cookie需要过期,这是删除已设置的Cookie的唯一方法。 - Sergey
同时,您不希望“过期”所有的cookie,只需要过期认证cookie。 - Mike
@Mike,这个解决方案怎么样?https://dev59.com/_Ww15IYBdhLWcg3wZ64Y#24961207? - Korayem
是的,这个例子有效,因为该人遍历了response上的所有cookie,并将它们更改为已过期,然后将这些过期的cookie发送到响应中,当客户端浏览器接收到它们时,它会自动删除它们,因为它们已经过期。HttpContext.Current.Request.Cookies.Clear();行修改了当前request对象,而不是响应 - 这意味着随着代码继续处理该请求,没有cookie可供使用。然而,响应仍然包含所有cookie,但已过期。 - Sergey
你的示例根本没有改变cookie的过期时间。...我必须承认,我不确定HttpOnly cookie是否需要以这种方式删除。可能只需要将它们移除即可。 - Sergey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接