【问题标题】:Http session issueHttp会话问题
【发布时间】:2026-02-07 18:20:03
【问题描述】:

我遇到了奇怪的会话问题。我开发了一个网站,它使用会话来跟踪用户特定信息,以确定特定用户是否有权访问网站的某些部分。我正在使用 VSTS 2008 + .Net 3.5 + C# 开发 ASP.Net 网站。

在我的设计中,当我访问http://mysite/sitemanager时,如果没有可用的会话ID,将要求用户输入他们的用户名和密码(如果通过密码检查,将授予可用的会话ID);如果会话 ID 可用,则表示用户具有站点管理权限并已通过身份验证,则用户应该可以访问站点管理器的所有功能 -- 即所有登录用户都有权访问站点管理器。

麻烦的场景是这样的,

  1. 我从新的IE窗口访问http://mysite/sitemanager,因为我之前没有登录过,我将使用我的凭据登录并授予站点管理权限,
  2. 然后我(不关闭IE)在同一IE窗口的地址栏中输入http://www.google.com替换http://mysite/sitemanager,谷歌出现,
  3. 然后我将地址http://mysite/sitemanager粘贴到同一个IE窗口中访问,我很惊讶我没有要求输入密码的权限。

任何想法有什么问题吗?我想要的是在步骤(3)中应该要求用户输入密码。

【问题讨论】:

    标签: c# asp.net .net session visual-studio-2008


    【解决方案1】:

    只有当用户删除服务器提供给他/她的会话 cookie 时,会话状态才会丢失。或者用户没有针对特定(Session.TimeOut 属性)时段提出请求。或者,如果您在代码中放弃它。

    【讨论】:

    • 谢谢 çağdaş,1. 你的意思是这是设计使然,而不是我在服务器端的代码错误? 2. 我认为会话是在cookie中实现的,也就是说即使我访问谷歌,IE仍然保留我的会话cookie为mysite/sitemanager?这很令人困惑,因为我更改了域(谷歌),但 IE 仍然保留以前域(mysite)的会话信息 3. 任何解决方案让用户在步骤(3)中输入他们的用户名和密码?
    • 1.是的,这是设计使然。你的代码没有错。 2.确实是cookie,但是关闭浏览器会被删除。 3. 我认为你做不到。另外,我认为您不应该尝试实现这一点。想象一下,您的用户在 Google 上搜索内容时正在浏览您的网站,并因此而退出您的网站。
    • 请记住,您可以设置 Session.Timeout 属性 (msdn.microsoft.com/en-us/library/ms525473.aspx) 让会话在 X 分钟后自动过期。至于共享计算机场景......好吧,除了为用户设置一个注销按钮之外,您真的无能为力。
    • 我已经读过了。但我不建议你走这条路。不要重新发明*。看看数以百万计的使用会员资格的网页,看看他们做了什么。
    • 好吧,总结一下。不要试图找到一种方法让您的用户在导航到另一个站点时退出。这只会使他们感到困惑,并且很可能会惹恼他们。至于我所说的“不要重新发明*”的意思是:不要试图创建一个新的登录系统(就像不要试图让你的用户在他们离开时注销)。只需适应被广泛接受的、被证明是有效的系统(比如 *.com。当我离开时它不会让我退出 :))。我希望这很清楚:)
    【解决方案2】:

    您的会话并没有仅仅因为您离开网站而结束。自上次与站点交互以来,会话在超时期限内保持活动状态。这就是会话信息仍然存在的原因。

    要回答您的评论,您可以通过调用 Session.Abandon() 来结束会话。如果您想在有人离开网站时执行此操作,我建议您对页面的卸载客户端事件进行 ajax 调用,该事件将依次调用 Session.Abandon() 或至少重置凭据。但是,这可能会很棘手,因为即使您将页面留给自己站点中的另一个页面,也会调用卸载,因此您也必须检查这一点。是的,这是设计使然。除非您另外指定,否则默认会话超时为 20 分钟。

    【讨论】:

    • 谢谢SirDemon,1. 你的意思是这是设计使然,而不是我在服务器端的代码错误? 2.有什么办法让用户在第(3)步输入用户名和密码?
    • 谢谢SirDemon,你有什么相关的棘手代码可以分享吗?我喜欢并想试试你的 Ajax 代码。 :-)
    • 如果我输入另一个 URL(在我的示例中是 Google)并转到新 URL,是否会触发卸载客户端事件?
    • 我的意思是卸载事件将在页面的任何卸载时触发,无论是离开到像谷歌这样的外部网站,还是你自己网站中的另一个页面。因此,代码需要确保当用户停留在您的站点内时它不会调用 session.Abandon()。
    • 感谢 SirDemon,1. 我之前没有使用过该事件,如果您能推荐一些代码示例以供快速参考,不胜感激?
    【解决方案3】:

    这就是网络会话无处不在的工作方式。避免让用户感到意外;你最好接受这种行为。


    但是,如果您真的希望您的用户在停止使用您的网站时注销,请按照以下方法...

    而不是使用 unload 事件(实施起来会有问题,因为很难判断某人何时真正离开您的网站 - 如果他们打开您网站的两个窗口会发生什么?),我建议将会话超时缩短到 1 分钟,并使用客户端保持活动状态:本质上,浏览器每隔几秒(例如 10 次)在预先确定的 url 处对服务器执行一次 ping 操作,除了保持会话活动状态之外,这绝对没有任何作用。

    如果需要,这可以完全不使用 javascript 来实现,通过 iframe 到带有元刷新标记的页面。当然,在 javascript 中它会更健壮和更简单,但隐藏的 iframe 并不太复杂,元标记也不是。如果服务器端刷新页面支持发送 304 Not-modified,你也将有一个开销非常低的解决方案。

    在您的主文件中,您总是会包含以下内容:

    <iframe src="keepalive.aspx" width="1" height="1" />
    <!--and perhaps use css to hide the iframe - but test that!-->
    

    在 keepalive.aspx 中你会包括:

    <meta http-equiv="refresh" content="5" />
    

    最后,作为带宽的优化,在keepalive.aspx的代码中,可以添加Last-Modified响应头,并检查浏览器是否发送了If-Not-Modified-Since请求标头,如果有,则发送 304 Not-Modified 而不是完整文档。

    最后,如果您无论如何都依赖于 javascript(许多此类基于登录的网络应用程序都是如此),那么您也可以简单地使用您最喜欢的 ajax 框架来定期执行请求 - 而不需要 iframe。

    【讨论】:

    • 谢谢 Eamon,为什么在“如果他们有两个打开您的站点的窗口”时使用 unload 事件来实现会出现问题,请告诉我更多细节吗?
    • 另一个有趣的点是,与使用 Last-Modified 响应头相比,使用 ajax 会显着减少服务器端的带宽和工作量吗?
    • 不,304-Not-modified 和 AJAX 在 CPU 和带宽方面都“几乎免费”;它们都可以用轻量级的自定义 IHttpHandler 来实现。如果这就是它所做的一切,您可能可以轻松地在一个盒子上为一百万客户提供服务 - 所以不用担心;您的瓶颈将在其他地方(例如,在会话中)。
    • 至于window.unload;这是有问题的,因为它可能并不总是触发,您需要 100% 确定卸载是由于在您的网站上加载页面还是由于加载另一个页面(维护麻烦),以及卸载是由于另一个站点和用户打开了第二个窗口,然后卸载将触发 Session.Abandon - 也破坏了第二个窗口。 keepalive 架构要简单得多。