本文介绍了ASP.NET_SessionId + OWIN Cookies 不会发送到浏览器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 Owin cookie 身份验证时遇到一个奇怪的问题.

I have a strange problem with using Owin cookie authentication.

当我启动 IIS 服务器时,身份验证在 IE/Firefox 和 Chrome 上运行良好.

When I start my IIS server authentication works perfectly fine on IE/Firefox and Chrome.

我开始使用身份验证进行一些测试并在不同平台上登录,但出现了一个奇怪的错误.偶尔,Owin 框架/IIS 不会向浏览器发送任何 cookie.我将输入正确的用户名和密码,代码运行但根本没有 cookie 被传送到浏览器.如果我重新启动服务器,它就会开始工作,然后在某个时候我会尝试登录,然后 cookie 再次停止传递.单步执行代码什么也不做,也不会抛出任何错误.

I started doing some testing with Authentication and logging in on different platforms and I have come up with a strange error. Sporadically the Owin framework / IIS just doesn't send any cookies to the browsers. I will type in a username and password which is correct the code runs but no cookie gets delivered to the browser at all. If I restart the server it starts working then at some point I will try login and again cookies stop getting delivered. Stepping over the code does nothing and throws no errors.

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            CookieHttpOnly = true,
            AuthenticationType = "ABC",
            LoginPath = new PathString("/Account/Login"),
            CookiePath = "/",
            CookieName = "ABC",
            Provider = new CookieAuthenticationProvider
               {
                  OnApplyRedirect = ctx =>
                  {
                     if (!IsAjaxRequest(ctx.Request))
                     {
                        ctx.Response.Redirect(ctx.RedirectUri);
                     }
                 }
               }
        });

在我的登录过程中,我有以下代码:

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
                            authenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

var authentication = HttpContext.Current.GetOwinContext().Authentication;
var identity = new ClaimsIdentity("ABC");
identity.AddClaim(new Claim(ClaimTypes.Name, user.Username));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.User_ID.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Role, role.myRole.ToString()));
    authentication.AuthenticationResponseGrant =
        new AuthenticationResponseGrant(identity, new AuthenticationProperties()
                                                   {
                                                       IsPersistent = isPersistent
                                                   });

authenticationManager.SignIn(new AuthenticationProperties() {IsPersistent = isPersistent}, identity);

更新 1: 问题的一个原因似乎是当我向会话添加项目时,问题就开始了.添加诸如 Session.Content["ABC"]=123 之类的简单内容似乎会造成问题.

Update 1: It seems that one cause of the problem is when I add items to session the problems start. Adding something simple like Session.Content["ABC"]= 123 seems to create the problem.

我能看出来的内容如下:1) (Chrome) 当我登录时,我得到 ASP.NET_SessionId + 我的身份验证 cookie.2)我转到设置 session.contents 的页面...3) 打开一个新的浏览器 (Firefox) 并尝试登录,但它没有收到 ASP.NET_SessionId 也没有收到 Authentication Cookie4) 虽然第一个浏览器有 ASP.NET_SessionId 它继续工作.我删除这个 cookie 的那一刻,它和所有其他浏览器都有同样的问题我正在处理 IP 地址 (10.x.x.x) 和 localhost.

What I can make out is as follows:1) (Chrome)When I login I get ASP.NET_SessionId + my authentication cookie.2) I go to a page that sets a session.contents...3) Open a new browser (Firefox) and try login and it does not receive an ASP.NET_SessionId nor does it get a Authentication Cookie4) Whilst the first browser has the ASP.NET_SessionId it continues to work. The minute I remove this cookie it has the same problem as all the other browsersI am working on ip address (10.x.x.x) and localhost.

更新 2: 在使用 OWIN 进行身份验证之前,首先在我的 login_load 页面上强制创建 ASPNET_SessionId.

Update 2: Force creation of ASPNET_SessionId first on my login_load page before authentication with OWIN.

1) 在我使用 OWIN 进行身份验证之前,我在登录页面上创建了一个随机的 Session.Content 值以启动 ASP.NET_SessionId2)然后我进行身份验证并进行进一步的会话3) 其他浏览器现在似乎可以工作

1) before I authenticate with OWIN I make a random Session.Content value on my login page to start the ASP.NET_SessionId2) then I authenticate and make further sessions3) Other browsers seem to now work

这很奇怪.我只能得出结论,这与 ASP 和 OWIN 认为它们属于不同的域或类似的东西有关.

This is bizarre. I can only conclude that this has something to do with ASP and OWIN thinking they are in different domains or something like that.

更新 3 - 两者之间的奇怪行为.

Update 3 - Strange behaviour between the two.

发现了其他奇怪的行为 - Owin 和 ASP 会话的超时不同.我看到的是,通过某种机制,我的 Owin 会话比我的 ASP 会话保持更长时间.所以在登录时:1.) 我有一个基于 cookied 的身份验证会话2.) 我设置了一些会话变量

Additional strange behaviour identified - Timeout of Owin and ASP session is different. What I am seeing is that my Owin sessions are staying alive longer than my ASP sessions through some mechanism. So when logging in:1.) I have a cookied based auth session2.) I set a few session variables

我的会话变量 (2) 在 owin cookie 会话变量强制重新登录之前死亡",这会导致整个应用程序出现意外行为.(此人已登录但并未真正登录)

My session variables(2) "die" before the owin cookie session variable forces re-login, which causes unexpected behaviour throughout my entire application. (Person is logged in but is not really logged in)

更新 3B

经过一番挖掘,我在页面上看到一些评论,说表单"身份验证超时和会话超时需要匹配.我认为通常两者是同步的,但无论出于何种原因,两者都不同步.

After some digging I saw some comments on a page that say the "forms" authentication timeout and session timeout need to match. I am thinking normally the two are in sync but for whatever reason the two are not in sync.

解决方法摘要

1) 在认证之前总是先创建一个会话.基本上在启动应用程序时创建会话 Session["Workaround"] = 0;

1) Always create a Session first before authentication. Basically create session when you start the application Session["Workaround"] = 0;

2) [实验性] 如果您坚持使用 cookie,请确保您的 OWIN 超时/长度比 web.config 中的 sessionTimeout 长(测试中)

2) [Experimental] if you persist cookies make sure your OWIN timeout / length is longer than your sessionTimeout in your web.config (in testing)

推荐答案

我遇到了同样的问题,并将原因追溯到 OWIN ASP.NET 托管实现.我会说这是一个错误.

I have encountered the same problem and traced the cause to OWIN ASP.NET hosting implementation. I would say it's a bug.

一些背景

我的发现基于这些程序集版本:

My findings are based on these assembly versions:

  • Microsoft.Owin,版本=2.0.2.0,文化=中性,PublicKeyToken=31bf3856ad364e35
  • Microsoft.Owin.Host.SystemWeb,版本=2.0.2.0,文化=中性,PublicKeyToken=31bf3856ad364e35
  • System.Web,版本=4.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a

OWIN 使用它自己的抽象来处理响应 Cookie (Microsoft.Owin.ResponseCookieCollection).此实现直接包装响应标头集合并相应地更新 Set-Cookie 标头.OWIN ASP.NET 主机 (Microsoft.Owin.Host.SystemWeb) 只是包装了 System.Web.HttpResponse 和它的标头集合.所以当通过 OWIN 创建新的 cookie 时,响应 Set-Cookie 头会直接改变.

OWIN uses it's own abstraction to work with response Cookies (Microsoft.Owin.ResponseCookieCollection). This implementation directly wraps response headers collection and accordingly updates Set-Cookie header. OWIN ASP.NET host (Microsoft.Owin.Host.SystemWeb) just wraps System.Web.HttpResponse and it's headers collection. So when new cookie is created through OWIN, response Set-Cookie header is changed directly.

但是 ASP.NET 也使用它自己的抽象来处理响应 Cookie.这作为 System.Web.HttpResponse.Cookies 属性公开给我们,并由密封类 System.Web.HttpCookieCollection 实现.此实现不直接包装响应 Set-Cookie 标头,而是使用一些优化和少量内部通知来显示它已更改的状态到响应对象.

But ASP.NET also uses it's own abstraction to work with response Cookies. This is exposed to us as System.Web.HttpResponse.Cookies property and implemented by sealed class System.Web.HttpCookieCollection. This implementation does not wrap response Set-Cookie header directly but uses some optimizations and handful of internal notifications to manifest it's changed state to response object.

然后在请求生命周期后期有一个点,其中 HttpCookieCollection 改变状态被测试 (System.Web.HttpResponse.GenerateResponseHeadersForCookies()) 并且 cookie 被序列化为 Set-Cookie 标头.如果此集合处于某种特定状态,则首先清除整个 Set-Cookie 标头,然后根据集合中存储的 cookie 重新创建.

Then there is a point late in request lifetime where HttpCookieCollection changed state is tested (System.Web.HttpResponse.GenerateResponseHeadersForCookies()) and cookies are serialized to Set-Cookie header. If this collection is in some specific state, whole Set-Cookie header is first cleared and recreated from cookies stored in collection.

ASP.NET 会话实现使用 System.Web.HttpResponse.Cookies 属性来存储它的 ASP.NET_SessionId cookie.在 ASP.NET 会话状态模块 (System.Web.SessionState.SessionStateModule) 中还有一些基本优化,通过名为 s_sessionEverSet 的静态属性实现,这是不言自明的.如果你曾经在你的应用程序中存储一些东西到会话状态,这个模块会为每个请求做更多的工作.

ASP.NET session implementation uses System.Web.HttpResponse.Cookies property to store it's ASP.NET_SessionId cookie. Also there is some basic optimization in ASP.NET session state module (System.Web.SessionState.SessionStateModule) implemented through static property named s_sessionEverSet which is quite self explanatory. If you ever store something to session state in your application, this module will do a little more work for each request.

回到我们的登录问题

通过所有这些片段,您的场景可以得到解释.

With all these pieces your scenarios can be explained.

案例 1 - 从未设置会话

System.Web.SessionState.SessionStateModule,s_sessionEverSet 属性为 false.会话状态模块不生成会话 ID,并且System.Web.HttpResponse.Cookies 集合状态未检测到已更改.在这种情况下,OWIN cookie 会正确发送到浏览器,并且可以正常登录.

System.Web.SessionState.SessionStateModule, s_sessionEverSet property is false. No session id's are generated by session state module and System.Web.HttpResponse.Cookies collection state is not detected as changed. In this case OWIN cookies are sent correctly to the browser and login works.

案例 2 - 会话在应用程序的某处使用,但在用户尝试进行身份验证之前未使用

System.Web.SessionState.SessionStateModule,s_sessionEverSet 属性为真.会话 ID 由 SessionStateModule 生成,ASP.NET_SessionId 被添加到 System.Web.HttpResponse.Cookies 集合中,但由于用户的会话实际上是空的,因此它在请求生命周期的后期被删除.在这种情况下,System.Web.HttpResponse.Cookies 集合状态被检测为已更改,并且 Set-Cookie 标头在 cookie 序列化为标头值.

System.Web.SessionState.SessionStateModule, s_sessionEverSet property is true. Session Id's are generated by SessionStateModule, ASP.NET_SessionId is added to System.Web.HttpResponse.Cookies collection but it's removed later in request lifetime as user's session is in fact empty. In this case System.Web.HttpResponse.Cookies collection state is detected as changed and Set-Cookie header is first cleared before cookies are serialized to header value.

在这种情况下,OWIN 响应 cookie 会丢失"并且用户未通过身份验证并被重定向回登录页面.

In this case OWIN response cookies are "lost" and user is not authenticated and is redirected back to login page.

案例 3 - 在用户尝试进行身份验证之前使用会话

System.Web.SessionState.SessionStateModule,s_sessionEverSet 属性为真.会话 ID 由 SessionStateModule 生成,ASP.NET_SessionId 添加到 System.Web.HttpResponse.Cookies.由于 System.Web.HttpCookieCollectionSystem.Web.HttpResponse.GenerateResponseHeadersForCookies() 的内部优化,Set-Cookie 标头不会首先被清除,但是仅更新.

System.Web.SessionState.SessionStateModule, s_sessionEverSet property is true. Session Id's are generated by SessionStateModule, ASP.NET_SessionId is added to System.Web.HttpResponse.Cookies. Due to internal optimization in System.Web.HttpCookieCollection and System.Web.HttpResponse.GenerateResponseHeadersForCookies() Set-Cookie header is NOT first cleared but only updated.

在这种情况下,OWIN 身份验证 cookie 和 ASP.NET_SessionId cookie 都被发送以作为响应和登录工作.

In this case both OWIN authentication cookies and ASP.NET_SessionId cookie are sent in response and login works.

关于 cookie 的更普遍的问题

如您所见,该问题更为普遍,不仅限于 ASP.NET 会话.如果您通过 Microsoft.Owin.Host.SystemWeb 托管 OWIN,并且您/某物直接使用 System.Web.HttpResponse.Cookies 集合,那么您将面临风险.

As you can see the problem is more general and not limited to ASP.NET session. If you are hosting OWIN through Microsoft.Owin.Host.SystemWeb and you/something is directly using System.Web.HttpResponse.Cookies collection you are at risk.

例如这有效并且两个 cookie 都正确发送到浏览器...

For example this works and both cookies are correctly sent to browser...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";

    return View();
}

但是这没有并且OwinCookie丢失"了...

But this does not and OwinCookie is "lost"...

public ActionResult Index()
{
    HttpContext.GetOwinContext()
        .Response.Cookies.Append("OwinCookie", "SomeValue");
    HttpContext.Response.Cookies["ASPCookie"].Value = "SomeValue";
    HttpContext.Response.Cookies.Remove("ASPCookie");

    return View();
}

均通过 VS2013、IISExpress 和默认 MVC 项目模板进行测试.

Both tested from VS2013, IISExpress and default MVC project template.

这篇关于ASP.NET_SessionId + OWIN Cookies 不会发送到浏览器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 10:13