清除缓存后 set-cookie 不适用于 IE11/10

set-cookie not working for IE11/10 after clearing cache

我目前遇到一个问题,即在清除 cache/cookies IE10 和 IE11 后将不再设置 cookie。请求和响应看起来几乎相同,但在清除缓存后,cookie 永远不会被传递,即使它似乎设置正确。

下面是我的登录方法流程:

 1. VerifyLogin()    -> Fail: Go To Login page
                     -> Pass: Call rest of the AJAX Methods // Enter Login Credentials and submit
 2. Authentication() -> Fail: Prompt the user
                     -> Pass: set forms auth cookie and navigate back to original page, where it will call VerifyLogin() again

一旦 Authentication() 通过,他们就应该顺利通过 VerifyLogin() 并继续使用该产品。现在,所有调用都将传递表单身份验证 cookie。

在我看到它失败的实例中,Authentication() 调用通过并获得 200 OK(并有一个 set-cookie 响应 header)但是,VerifyLogin() 然后失败,因为它还没有放弃饼干。

我很难重现这个,但到目前为止我的重现步骤如下。这是从没有 IE 运行 的实例开始的。我不是 100% 确定这与我的客户遇到的问题完全相同,但它似乎揭示了他们所看到的相同问题。

  1. 启动 IE
  2. 浏览到站点的索引页面并跳转到登录页面(验证失败)
  3. 使用凭据登录,Authentication() returns 200 OK 并有 set-cookie 响应 header。然后它会导航您并调用通过的 VerifyLogin() 。 cookie 在请求中发送,并且全部成功。随后调用所有工作。
  4. 清除我的缓存和 cookies
  5. 浏览到站点的索引页面并跳转到登录页面(验证失败,这是应该的)
  6. 使用凭据登录,Authentication() returns 200 OK 并有 set-cookie 响应 header。然后它会引导您并在此时调用 VerifyLogin() 失败。 cookie 不会在请求中传递,即使它先前已在 Authentication() 的响应中设置。如果我关闭并重新打开 IE,它将再次工作。

所以,就像第二次 set-cookie 响应只是没有设置 cookie。

首先,这是我的 web.config 的相关部分以及我如何设置表单 cookie。

web.config:

 <authentication mode="Forms">
      <forms enableCrossAppRedirects="true" name="Gator.Express.Auth" timeout="2880" />
    </authentication>

setAuthenticationCookie 方法:

 public void SetAuthenticationCookie(string userName, CookieData cookieData)
        {
            //In order to pickup the settings from config, we create a default cookie and use its values to create a 
            //new one.
            var cookie = FormsAuthentication.GetAuthCookie(userName, true);
            var ticket = FormsAuthentication.Decrypt(cookie.Value);

            if (ticket == null)
                throw new Exception("Error setting authorisation cookie. Decryption of default cookie failed.");

            var jsonToken = JsonConvert.SerializeObject(cookieData);

            var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
                ticket.IsPersistent, jsonToken, ticket.CookiePath);
            var encTicket = FormsAuthentication.Encrypt(newTicket);

            cookie.Value = encTicket;

            HttpContext.Current.Response.Cookies.Add(cookie);
        }

下面是请求和响应的顺序。

工作验证请求

POST http://localhost:55733/api/Authentication HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:61496/Login.html
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 35
DNT: 1
Host: localhost:55733
Pragma: no-cache

Username=michaelGator&Password=XXXX

# 工作验证响应

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
Set-Cookie: Gator.Express.Auth=01020FCCF4658183D208FE0F4CC8BA1385D208000C6D00690063006800610065006C004700610074006F00720000012F00FF; path=/; HttpOnly
Set-Cookie: Gator.Express.Auth=0102054E17668183D208FE05CEEABA1385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF; expires=Sun, 05-Jul-2015 08:28:39 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcQXV0aGVudGljYXRpb24=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:28:39 GMT
Content-Length: 14

"michaelGator"

# 工作验证登录请求

GET http://localhost:55733/api/VerifyLogin HTTP/1.1
Referer: http://localhost:61496/
Accept: */*
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost:55733
Cookie: Gator.Express.Auth=0102054E17668183D208FE05CEEABA1385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF

# 工作 VerifyLogin 响应

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcVmVyaWZ5TG9naW4=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:28:39 GMT
Content-Length: 0

下面是 non-working 组请求和响应。请注意,身份验证方法 returns 一个 200 OK 和一个 set-cookie 命令,但在下一个验证登录调用中,cookie 消失了。

# 身份验证请求 - Returns 它应该是 non-working 请求集的一部分

POST http://localhost:55733/api/Authentication HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost:61496/Login.html
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 35
DNT: 1
Host: localhost:55733
Pragma: no-cache

Username=michaelGator&Password=XXXX

# 身份验证响应- Returns 它应该是 non-working 请求集的一部分

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
Set-Cookie: Gator.Express.Auth=01022054EB9B8183D208FE20D4BEF01385D208000C6D00690063006800610065006C004700610074006F00720000012F00FF; path=/; HttpOnly
Set-Cookie: Gator.Express.Auth=01028447109C8183D208FE84C7E3F01385D208010C6D00690063006800610065006C004700610074006F007200377B002200530073006F004100630063006F0075006E0074004900640022003A002200300030003000300030003000300030002D0030003000300030002D0030003000300030002D0030003000300030002D0030003000300030003000300030003000300030003000300022007D00012F00FF; expires=Sun, 05-Jul-2015 08:30:10 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcQXV0aGVudGljYXRpb24=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:30:10 GMT
Content-Length: 14

"michaelGator"

# Non-Working 验证登录请求 - 注意,没有 cookie 传递

GET http://localhost:55733/api/VerifyLogin HTTP/1.1
Referer: http://localhost:61496/
Accept: */*
Accept-Language: en-GB
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
DNT: 1
Host: localhost:55733

# Non-Working VerifyLogin 响应 - 失败,因为没有传递任何 Forms Cookie

HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcV29ya2luZ1xnYXRvci5nYXRvcndlYnNlcnZpY2VcU291cmNlXEdhdG9yV2ViU2VydmljZVxhcGlcVmVyaWZ5TG9naW4=?=
Access-Control-Allow-Origin: http://localhost:61496
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, token
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 03 Jul 2015 08:30:10 GMT
Content-Length: 71

{"$id":"1","Message":"Authorization has been denied for this request."}

有人对此有什么想法吗?

  1. 为什么响应发送两个 SetCookie headers 具有相同的 cookie 名称?这似乎……错误且令人困惑。

  2. 注意不要给 IE 过多的 cookie 数据。您的 cookie 值很长! cookie 限制为 ~4k。这是您域的 cookie 总数。如果超过这个长度,IE 将不会返回。

HTH

您似乎获得了两个身份验证 cookie,这表明您的实施与 ASP.Net 试图为您自动执行的内容发生冲突。

有一个 FormsAuthentication.SetAuthCookie 创建和设置 cookie,我认为这已经应用了,所以:

  1. FormsAuthentication.SetAuthCookie 获取 cookie(已在同一响应中设置)。
  2. 你的 SetAuthenticationCookie 开火了。
  3. 这会调用 FormsAuthentication.GetAuthCookie 并处理(将 JSON 序列化数据嵌入到新的 cookie 中)原始数据。
  4. 您调用 HttpContext.Current.Response.Cookies.Add 创建第二个 cookie。
  5. 两个 cookie 在 header 中以相同的名称
  6. 传送

你没有清除原始cookie,.Net不知道如何处理你处理过的cookie。

我想你有两个选择:

  1. 将您的 JSON 数据拆分到一个完全独立的 cookie 中,并使用不同的名称。
  2. 从头开始制作您自己的 cookie,不要使用 .Net 的任何 FormsAuthentication 方法。

我个人认为前者是最简单、实施起来最快的。

尝试 cookie 名称可能也值得 - 我不确定所有浏览器都支持 cookie 名称中的句点,但它们都区分大小写。

最后还有一些值得检查的东西 - 它几乎是 never worth setting a cookie's path in .Net,因为 IIS 将 URL 视为不区分大小写,但浏览器都将 cookie 名称视为 case-sensitive。