为什么XMLHttpRequest.withCredentials即使对于相同的站点Ajax请求也是必需的

时间:2016-11-21 16:51:18

标签: cookies cors

我正在尝试实现部署在与我的登录页面服务器不同的HTTP服务器中的身份验证服务。

下图描绘了我的设置: enter image description here

在第1步,我的浏览器发出HTTP GET请求以获取登录页面。这是作为#2中的HTTP响应提供的。我的浏览器呈现登录页面,当我单击登录按钮时,我将HTTP POST发送到另一台服务器(在同一本地主机上)。这是在#3中完成的。身份验证服务器检查登录详细信息并发送响应以在#4中设置cookie。

#3中的ajax POST请求是使用jQuery创建的:

$.post('http://127.0.0.1:8080/auth-server/some/path/',
       {username: 'foo', password: 'foo'},
       someCallback);

身份验证服务的响应(假设身份验证成功)具有以下标头:

HTTP/1.1 200
Set-Cookie: session-id=v3876gc9jf22krlun57j6ellaq;Version=1
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: origin, content-type, accept, authorization
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 21 Nov 2016 16:17:08 GMT

所以cookie(session-id)出现在步骤#4的HTTP响应中。

现在,如果用户再次尝试登录,我希望身份验证服务能够检测到这一点。为了测试该场景,我再次按下登录按钮以重复#3中的帖子。我原本期望第二个请求包含cookie。但是,当我第二次按下登录按钮时,#3中发送的帖子中的请求标题不包含cookie。

我发现,对于#3中包含cookie的帖子,我必须这样做:

        $.ajax({
            type: 'post',
            url: 'http://127.0.0.1:8080/auth-server/some/path',
            crossDomain: true,
            dataType: 'text',
            xhrFields: {
                withCredentials: true
            },
            data: {
                username : 'foo',
                password : 'foo',
            },
            success: someCallback
        });

为什么这是必要的? MDN声明这只是跨站点请求所必需的。 This SO post也使用xhrFields,但仅限于跨域方案。我知道我的情况不是跨域的,因为服务脚本的页面都在localhost上,而发送ajax请求的页面位于同一主机上。我也了解cookie域名为not port specific。此外,由于我的cookie未明确指定域,因此the effective domain is that of the request表示127.0.0.1,这与我第二次发送POST请求(#3)时相同。最后,#4上的HTTP响应已经包含Access-Control-Allow-Origin: *,这意味着资源can be accessed by any domain in a cross-site manner

那么为什么我必须使用xhrFields: {withCredentials: true}来完成这项工作呢?

我的理解是,设置Access-Control-Allow-Origin: *只是启用跨网站请求,但为了发送Cookie,应该使用xhrFields: {withCredentials: true}(如MDN section on requests with credentials中所述) )。此外,我了解该请求确实是跨站点的,因为在决定请求是否是跨站点时,端口号很重要。 cookie的域是否包含端口是无关紧要的。这种理解是否正确?

更新

我认为在this answer中已经非常清楚地解释了这一点,所以也许应该删除这个问题。

1 个答案:

答案 0 :(得分:4)

原点的所有部分必须与主机(ajax目标)匹配才能被视为同源。例如,原始https://sales.company.com:9443的3部分包括:

  1. 协议/方案( https - 与http不匹配)
  2. 主机名( sales.company.com - 与subdomain.sales.company.com不匹配)
  3. port( 9443 - 与443不匹配)
  4. enter image description here

    请参阅https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy