把我的头砸得太久了。如何防止用户在使用 FormsAuthentication.SignOut 注销后浏览网站页面?我希望这样做:
FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();
但事实并非如此。如果我直接输入 URL,我仍然可以浏览到该页面。我有一段时间没有使用自己滚动的安全性了,所以我忘记了为什么这不起作用。
把我的头砸得太久了。如何防止用户在使用 FormsAuthentication.SignOut 注销后浏览网站页面?我希望这样做:
FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();
但事实并非如此。如果我直接输入 URL,我仍然可以浏览到该页面。我有一段时间没有使用自己滚动的安全性了,所以我忘记了为什么这不起作用。
用户仍然可以浏览您的网站,因为在您致电时不会清除 cookie,FormsAuthentication.SignOut()
并且它们会在每次新请求时进行身份验证。在 MS 文档中说 cookie 将被清除,但它们不会,错误?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 参考。
使用 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 上面给出了注销后如何防止缓存的例子:
您需要通过 Response 在客户端使缓存无效。
// 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" );
}
在我看来,您的 web.config 授权部分没有在 . 请参阅下面的示例。
<authentication mode="Forms">
<forms name="MyCookie" loginUrl="Login.aspx" protection="All" timeout="90" slidingExpiration="true"></forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
这里的关键是你说“如果我直接输入一个 URL……”。
默认情况下,在表单身份验证下,浏览器会为用户缓存页面。因此,直接从浏览器地址框下拉列表中选择一个 URL,或者输入它,可以从浏览器的缓存中获取页面,并且永远不会返回服务器检查身份验证/授权。对此的解决方案是防止在每个页面的 Page_Load 事件或基本页面的 OnLoad() 中进行客户端缓存:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
您可能还想致电:
Response.Cache.SetNoStore();
我以前也为此苦苦挣扎过。
下面是似乎正在发生的事情的一个类比... 新访问者 Joe 来到该站点并使用 FormsAuthentication 通过登录页面登录。ASP.NET 为 Joe 生成了一个新身份,并给了他一个 cookie。那块饼干就像房子的钥匙,只要乔带着那把钥匙回来,他就可以打开锁。每位访客都会获得一把新钥匙和一把新锁以供使用。
当FormsAuthentication.SignOut()
被调用时,系统会告诉 Joe 丢失密钥。通常,这是可行的,因为乔不再拥有钥匙,他无法进入。
但是,如果乔回来了,并且确实有那把丢失的钥匙,他就会被放回去!
据我所知,没有办法告诉 ASP.NET 更改门上的锁!
我可以忍受的方式是在 Session 变量中记住 Joe 的名字。当他注销时,我放弃了会话,所以我不再知道他的名字了。稍后,为了检查他是否被允许进入,我只需将他的 Identity.Name 与当前会话的内容进行比较,如果它们不匹配,则他不是有效的访问者。
简而言之,对于一个网站,如果不User.Identity.IsAuthenticated
检查您的 Session 变量,请不要依赖!
经过大量搜索终于这对我有用。我希望它有所帮助。
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>
这对我有用
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());
}
通常要清除用户会话,执行
HttpContext.Session.Abandon();
FormsAuthentication.SignOut();
将有效地注销用户。但是,如果在同一个请求中您需要检查Request.isAuthenticated
(例如,在授权过滤器中可能经常发生),那么您会发现
Request.isAuthenticated == true
甚至 _after 你做了HttpContext.Session.Abandon()
和FormsAuthentication.SignOut()
.
唯一有效的就是做
AuthenticationManager.SignOut();
HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
这有效地设置了Request.isAuthenticated = false
.
您发布的代码看起来应该正确删除表单身份验证令牌,因此有问题的文件夹/页面可能实际上并未受到保护。
您是否确认在登录之前无法访问这些页面?
您可以发布您正在使用的 web.config 设置和登录代码吗?
我一直在为我的所有页面编写一个基类,我遇到了同样的问题。我有如下代码,但它不起作用。通过跟踪,控制从 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() 方法不是问题,重定向方法是问题。
我希望这可以帮助某人
问候
我只是在这里尝试了一些建议,虽然我能够使用浏览器后退按钮,但当我单击菜单选择时,该 [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);
}
尽管浏览器上的后退功能让我返回并显示了安全菜单(我仍在努力),但我无法执行应用程序中的任何安全操作。
希望这可以帮助
我在这个线程中尝试了大多数答案,没有运气。结束了这个:
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();
}
当我设置authentication > forms > Path 属性时,这开始发生在我身上Web.config
。删除它解决了问题,并且FormsAuthentication.SignOut();
再次简单地删除了 cookie。
可能是您从一个子域 (sub1.domain.com) 登录,然后尝试从另一个子域 (www.domain.com) 注销。
我刚刚遇到了同样的问题,SignOut() 似乎无法正确删除票证。但仅在特定情况下,某些其他逻辑导致重定向。在我删除了第二个重定向(用错误消息替换它)后,问题就消失了。
问题一定是页面在错误的时间重定向,因此没有触发身份验证。
我现在有一个类似的问题,我相信我的问题以及原始海报是因为重定向。默认情况下, Response.Redirect 会导致一个异常立即冒泡,直到它被捕获并立即执行重定向,我猜这会阻止修改后的 cookie 集合被传递给客户端。如果您修改代码以使用:
Response.Redirect("url", false);
这可以防止异常,并且似乎允许将 cookie 正确发送回客户端。
只需在您按下登录时尝试发送会话变量。在欢迎页面上,首先在页面加载或 Init 事件中检查该会话是否为空:
if(Session["UserID"] == null || Session["UserID"] == "")
{
Response.Redirect("Login.aspx");
}
我想添加一些信息来帮助理解问题。表单身份验证允许将用户数据存储在 cookie 或 URL 的查询字符串中。您的站点支持的方法可以在 web.config 文件中进行配置。
根据微软:
如果 CookiesSupported 为 false ,则SignOut 方法会从 cookie 或 URL 中删除表单身份验证票信息。
同时,他们说:
指示应用程序是否配置为无 cookie 表单身份验证的 HttpCookieMode 值之一。默认值为UseDeviceProfile 。
最后,关于 UseDeviceProfile,他们说:
如果 CookieMode 属性设置为 UseDeviceProfile, 如果当前请求的浏览器同时支持 cookie 和使用 cookie 进行重定向,则CookiesSupported 属性将返回 true ;否则,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 才能正常运行。
对我来说,以下方法有效。我认为如果在“FormsAuthentication.SignOut()”语句之后有任何错误,SingOut 不起作用。
public ActionResult SignOut()
{
if (Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
return Redirect("~/");
}
return View();
}
您是否正在使用 IE 测试/查看此行为?IE 可能正在从缓存中提供这些页面。众所周知,让 IE 刷新它的缓存非常困难,因此在很多情况下,即使在您注销后,键入“安全”页面之一的 url 也会显示之前的缓存内容。
(即使您以其他用户身份登录,我也看到过这种行为,并且 IE 在您的页面顶部显示“欢迎”栏,并带有旧用户的用户名。现在,通常重新加载会更新它,但如果它是持久的,它仍然可能是一个缓存问题。)
执行 Session.abandon() 并销毁 cookie 效果很好。我正在使用 mvc3,如果您转到受保护的页面、注销并通过浏览器历史记录,似乎会出现问题。没什么大不了的,但还是有点烦人。
尝试通过我的网络应用程序上的链接以正确的方式工作。
将其设置为不进行浏览器缓存可能是可行的方法。
对于 MVC,这对我有用:
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
}
请注意,如果来自 STS 的 wsignoutcleanup 消息与来自 IIS 的应用程序名称不匹配,WIF拒绝告诉浏览器清理 cookie,我的意思是CASE SENSITIVE。WIF 以绿色的 OK 检查作为响应,但不会向浏览器发送删除 cookie 的命令。
所以,你需要注意你的网址的大小写敏感。
例如,ThinkTecture Identity Server 将访问的 RP 的 url 保存在一个 cookie 中,但它使它们全部小写。WIF 将收到小写的 wsignoutcleanup 消息,并将其与 IIS 中的应用程序名称进行比较。如果不匹配,它不会删除任何 cookie,但会向浏览器报告 OK。因此,对于这个 Identity Server,我需要将 web.config 中的所有 url 和 IIS 中的所有应用程序名称都写成小写,以避免出现此类问题。
如果您有 STS 子域之外的应用程序,也不要忘记在浏览器中允许第三方 cookie,否则即使 WIF 告诉他,浏览器也不会删除 cookie。