为啥即使对于同一个站点 Ajax 请求也需要 XMLHttpRequest.withCredentials
Posted
技术标签:
【中文标题】为啥即使对于同一个站点 Ajax 请求也需要 XMLHttpRequest.withCredentials【英文标题】:why is XMLHttpRequest.withCredentials necessary even for same site Ajax requests为什么即使对于同一个站点 Ajax 请求也需要 XMLHttpRequest.withCredentials 【发布时间】:2017-04-05 03:38:45 【问题描述】:我正在尝试实现一个身份验证服务,该服务部署在与我的登录页面不同的 HTTP 服务器中。
下图描述了我的设置:
在第 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
,但仅与跨域场景有关。我知道我的情况不是跨域的,因为提供脚本的页面都在本地主机上,而发送 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已经解释的很清楚了,所以也许这个问题应该删掉。
【问题讨论】:
是的,但是他们使用不同的端口...这已经被认为是 CORS 【参考方案1】:源的所有部分都必须与主机(ajax 目标)匹配,才能被视为同源。来源https://sales.company.com:9443
的3部分例如包括:
-
协议/方案(https - 与 http 不匹配)
主机名(
sales.company.com
- 与 subdomain.sales.company.com
不匹配)
端口(9443 - 不匹配 443)
见https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
【讨论】:
以上是关于为啥即使对于同一个站点 Ajax 请求也需要 XMLHttpRequest.withCredentials的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 PDF 生成进程会锁定我站点中的其他 ajax 进程?
即使正确设置了 document.domain,跨子域 ajax 请求也会被拒绝