ASP.NET:请求之间的 Session.SessionID 变化

Posted

技术标签:

【中文标题】ASP.NET:请求之间的 Session.SessionID 变化【英文标题】:ASP.NET: Session.SessionID changes between requests 【发布时间】:2011-02-21 21:03:26 【问题描述】:

为什么 ASP.NET 页面中 Session 对象上的属性 SessionID 在请求之间会发生变化?

我有一个这样的页面:

...
<div>
    SessionID: <%= SessionID %>
</div>
...

每次我按 F5 时输出都会不断变化,与浏览器无关。

【问题讨论】:

【参考方案1】:

这就是原因

使用基于 cookie 的会话状态时,ASP.NET 在使用 Session 对象之前不会为会话数据分配存储空间。因此,在访问会话对象之前,会为每个页面请求生成一个新的会话 ID。如果您的应用程序需要整个会话的静态会话 ID,您可以在应用程序的 Global.asax 文件中实现 Session_Start 方法并将数据存储在 Session 对象中以修复会话 ID,或者您可以在您的另一部分中使用代码应用程序将数据显式存储在 Session 对象中。

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.sessionid.aspx

所以基本上,除非您在后端访问会话对象,否则每个请求都会生成一个新的 sessionId

编辑

此代码必须添加到文件 Global.asax 中。它向 Session 对象添加一个条目,以便您修复会话直到它过期。

protected void Session_Start(Object sender, EventArgs e) 

    Session["init"] = 0;

【讨论】:

我不知道,从来没有遇到过问题,但知道这很有趣 @Claudio 你能不能只输入一行代码,你的答案就完美了。有趣的信息来自一个有趣的问题......加上一个? ;) 有趣的是,这解决了我的问题 - 但问题仅在使用代码库大约 6 个月没有问题后才显现出来。我想不出为什么会突然改变的任何原因 - 任何人都可以提出为什么 sessionid 会突然重置的原因,而之前没有? @KumarHarsh:一旦您在会话中存储任何对象,会话 ID 将被修复。这就是我想说的“除非你在后端访问你的会话对象......”。一旦您分配了someid,会话将保持不变。考虑到这个答案已经超过 4 年了,不确定是否有与此相关的任何修改。 我注意到只需将没有任何内容的 Session_Start 方法添加到我的 Global.asax 中就可以了。不过感谢@Claudio 的提示。【参考方案2】:

还有另一个更隐蔽的原因,即使在 Session 对象已被初始化(如 Claudio 所证明的那样)时也会发生这种情况。

在 Web.config 中,如果有一个设置为 requireSSL="true"&lt;httpCookies&gt; 条目,但您实际上并未使用 HTTPS:对于特定请求,则不会发送会话 cookie(或者可能不会返回,我不确定是哪个),这意味着您最终会为每个请求创建一个全新的会话。

我发现这是一个艰难的过程,在我的源代码管理中的几次提交之间来回花费了几个小时,直到我发现什么特定的更改破坏了我的应用程序。

【讨论】:

我知道这一点,但仍然每隔 3 个月左右就会忘记它,并花几个小时调试.. 就我而言,我在 localhost 上进行测试,web.config 中的“requireSSL”设置为“true”。谢谢。 这是我的情况,我花了太多时间试图弄清楚(有一个红鲱鱼与不同的 web.config 文件)。 您的上述建议在 2018 年仍然有帮助。这是最常见的情况。谢谢!【参考方案3】:

在我的情况下,我发现会话 cookie 有一个包含 www. 前缀的 ,而我请求的页面没有 www.。 将www. 添加到URL 立即解决了问题。后来我将cookie的域设置为.mysite.com而不是www.mysite.com

【讨论】:

【参考方案4】:

我的问题是我们在 web.config 中设置了这个

&lt;httpCookies httpOnlyCookies="true" requireSSL="true" /&gt;

这意味着在非 SSL(默认)下调试时,auth cookie 不会被发送回服务器。这意味着服务器将为每个请求发送一个新的 auth cookie(带有一个新会话)给客户端。

解决方法是在 web.config 中将 requiressl 设置为 false,在 web.release.config 中设置为 true,或者在调试时打开 SSL:

【讨论】:

这与 Neville Cook 2011 年的回答有何不同?【参考方案5】:

使用 Neville 的回答(在 web.config 中删除 requireSSL = true)稍微修改 Joel Etherton 的代码,这里是应该处理在 SSL 模式和非 SSL 模式下运行的网站的代码,取决于用户和页面(我正在跳回到代码中,尚未在 SSL 上对其进行测试,但希望它应该可以工作 - 稍后会太忙而无法回到这个,所以这里是:

if (HttpContext.Current.Response.Cookies.Count > 0)
        
            foreach (string s in HttpContext.Current.Response.Cookies.AllKeys)
            
                if (s == FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid")
                
                    HttpContext.Current.Response.Cookies[s].Secure = HttpContext.Current.Request.IsSecureConnection;
                
            
        

【讨论】:

【参考方案6】:

导致 SessionID 在请求之间发生变化的另一种可能性是,即使已定义 Session_OnStart 和/或已初始化 Session,也可能是 URL 主机名包含无效字符(例如下划线)。我相信这是 IE 特定的(未验证),但如果您的 URL 是 http://server_name/app,那么 IE 将阻止所有 cookie,并且您的会话信息将无法在请求之间访问。

事实上,每个请求都会在服务器上启动一个单独的会话,因此如果您的页面包含多个图像、脚本标签等,那么这些 GET 请求中的每一个都会在服务器上产生不同的会话。

更多信息:http://support.microsoft.com/kb/316112

【讨论】:

【参考方案7】:

我的问题与 Microsoft MediaRoom IPTV 应用程序有关。事实证明,MPF MRML 应用程序不支持 cookie。更改为在 web.config 中使用无 cookie 会话解决了我的问题

<sessionState cookieless="true"  />

这是一篇关于它的非常古老的文章: Cookieless ASP.NET

【讨论】:

【参考方案8】:

在我的情况下,这是因为我在从外部应用程序中的网关重定向之后修改会话 ,所以因为我在该页面 url 中的 localhost 上使用 IP 而不是它实际上被认为是不同的网站不同的会话。

总结

如果您在 IIS 而不是 IIS express 上调试托管应用程序并在不同页面中混合您的机器 http://Ip 和 http://localhost,请多加注意

【讨论】:

【参考方案9】:

就我而言,这在我的开发和测试环境中经常发生。在尝试了上述所有解决方案均未成功后,我发现我可以通过删除所有会话 cookie 来解决此问题。 Web 开发者扩展使这很容易做到。我主要使用 Firefox 进行测试和开发,但在 Chrome 中测试时也发生了这种情况。该修复也适用于 Chrome。

我还没有在生产环境中执行此操作,也没有收到任何关于人们无法登录的报告。这似乎也只是在使会话 cookie 安全后才会发生。过去他们不安全时从未发生过。

更新:这只是在我们更改会话 cookie 以使其安全后才开始发生的。我确定确切的问题是由于浏览器中有两个或多个会话 cookie 具有相同的路径和域。始终存在问题的那个是具有空值或空值的那个。删除该特定 cookie 后,问题已解决。我还在 Global.asax.cs Sessin_Start 方法中添加了代码来检查这个空 cookie,如果是的话,将它的过期日期设置为过去的某个时间。

HttpCookieCollection cookies = Response.Cookies;
for (int i = 0; i < cookies.Count; i++)

    HttpCookie cookie = cookies.Get(i);

    if (cookie != null)
    
        if ((cookie.Name == "ASP.NET_SessionId" || cookie.Name == "ASP.NET_SessionID") && String.IsNullOrEmpty(cookie.Value))
        
            //Try resetting the expiration date of the session cookie to something in the past and/or deleting it.
            //Reset the expiration time of the cookie to one hour, one minute and one second in the past
            if (Response.Cookies[cookie.Name] != null)
                Response.Cookies[cookie.Name].Expires = DateTime.Today.Subtract(new TimeSpan(1, 1, 1));
        
    

【讨论】:

【参考方案10】:

从 .NET 4.7.2 开始,这对我来说发生了变化,这是由于会话 cookie 上的 SameSite 属性。更多信息请看这里:https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/

默认值更改为“Lax”并开始破坏。我将其更改为“无”,一切正常。

【讨论】:

【参考方案11】:

请确保您没有非常短的会话超时,并且如果您使用基于 cookie 的会话,请确保您正在接受该会话。

FireFox webDeveloperToolbar 有时会很有帮助,因为您可以看到为您的应用程序设置的 cookie。

【讨论】:

我猜我的会话超时未设置为低于一秒。每次快速按 F5 键都会改变。【参考方案12】:

会话 ID 重置可能有多种原因。但是,上面提到的任何内容都与我的问题无关。所以我会描述它以供将来参考。

在我的例子中,在每个请求上创建一个新会话会导致无限重定向循环。重定向动作发生在 OnActionExecuting 事件中。

此外,我一直在清除所有 http 标头(也在 OnActionExecuting 事件中使用 Response.ClearHeaders 方法),以防止在客户端缓存站点。但是该方法会清除所有标题,包括有关用户会话的信息,因此会清除临时存储中的所有数据(我稍后在程序中使用)。因此,即使在 Session_Start 事件中设置新会话也无济于事。

为了解决我的问题,我确保在发生重定向时不删除标头。

希望对某人有所帮助。

【讨论】:

【参考方案13】:

我以不同的方式遇到了这个问题。即使我在应用程序启动时在原始会话中设置了一个值,具有此属性 [SessionState(SessionStateBehavior.ReadOnly)] 的控制器仍在从不同的会话中读取。我正在通过 _layout.cshtml 添加会话值(也许不是最好的主意?)

显然是 ReadOnly 导致了问题,因为当我删除该属性时,原始会话(和 SessionId)将保持不变。使用克劳迪奥/微软的解决方案修复了它。

【讨论】:

【参考方案14】:

我使用的是 .NET Core 2.1,我很清楚问题不在于 Core。然而互联网缺乏,谷歌把我带到了这里,所以希望能帮别人节省几个小时。


Startup.cs

services.AddCors(o => o.AddPolicy("AllowAll", builder =>
            
                builder
                    .WithOrigins("http://localhost:3000")     // important
                    .AllowCredentials()                       // important
                    .AllowAnyMethod()
                    .AllowAnyHeader();       // obviously just for testing
            ));

client.js

const resp = await fetch("https://localhost:5001/api/user", 
            method: 'POST',
            credentials: 'include',                           // important
            headers: 
                'Content-Type': 'application/json'
            ,
            body: JSON.stringify(data)
        )

Controllers/LoginController.cs

namespace WebServer.Controllers

    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    
        [HttpPost]
        public IEnumerable<string> Post([FromBody]LoginForm lf)
        
            string prevUsername = HttpContext.Session.GetString("username");
            Console.WriteLine("Previous username: " + prevUsername);

            HttpContext.Session.SetString("username", lf.username);

            return new string[]  lf.username, lf.password ;
        
    

请注意,会话写入和读取工作正常,但似乎没有 cookie 传递给浏览器。至少我在任何地方都找不到“Set-Cookie”标头。

【讨论】:

以上是关于ASP.NET:请求之间的 Session.SessionID 变化的主要内容,如果未能解决你的问题,请参考以下文章

一个能够在Asp.Net和Asp.NetCore之间能够互相通讯的Rpc

ASP.NET页面之间传值的方式之Session(个人整理)

在ASP.NET和ASP.NET Core之间互相通讯的Rpc

使用 HttpClient 压缩对 asp.net core 2 站点的请求的最佳方法是啥?

请求内容意外结束 Kestrel ASP.NET Core

ASP.NET网站中实现Ajax的跨域请求