我在www.example.com上有一个webapp,在api.example.com上有一个API。
webapp对API进行ajax调用。
在某个地方,我需要在api.example.com上放置一个cookie来保持会话跟踪。
为了跟踪我的问题,我在webapp和api的两个子域上设置了测试cookie。 webapp在.exemple.com上设置了一个cookie,api在.exemple.com上设置了一个,在api.exemple.com上设置了另一个。 Cookies仅使用Domain = .exemple.com设置。没有路径,没有HTTPOnly。
注意:最后我只需要api.exemple.com上的一个。但这些是用于测试的。
使用我的浏览器(Firefox 16)进行直接查询工作正常。 查询api:设置并发送两个cookie。 在www上查询:设置了cookie,并且也发送了来自api的两个。 (当我在api之后查询www时)。
现在,我清理浏览器cookie并仅查询www。 在www上查询:工作正常,与以前一样。 关于api的子查询,来自www的ajax请求:不发送cookie。 Set-Cookies什么都不做。使用Firebug我在响应中看到了cookie。但是在后续请求或页面信息中没有它们的痕迹。
我事件尝试在Firefox上启用Cookie登录。绝对没有来自api的cookie的痕迹,甚至没有拒绝通知。
最后我只需要一种在api上存储一个cookie的方法。为此,我非常开放:)
信息: 这两个服务器是NodeJS。 我尝试在服务器端设置cookie(Set-Cookie标头),在客户端(document.cookies),手动使用firebug。
其他帖子我已经检查过没有解决方案(以及其他许多我不记得的):
setting cross-subdomain cookie with javascript
Can subdomain.example.com set a cookie that can be read by example.com?
答案 0 :(得分:41)
Access-Control-Allow-Credentials: true
withCredentials
作为请求$.ajax({
url: a_cross_domain_url,
xhrFields: {
withCredentials: true
}
});
否则XMLHttpRequest
将不发送Cookie,无论Access-Control-Allow-Credentials
标头如何。
Access-Control-Allow-Origin
Access-Control-Allow-Origin: http://www.example.com
通配符*
无效。如果设置了withCredentials
,浏览器将放弃响应。
参考文献:
http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
https://developer.mozilla.org/en-US/docs/HTTP_access_control
http://arunranga.com/examples/access-control/credentialedRequest.html
答案 1 :(得分:1)
除了 Alexandre 的正确答案,这是我通过 .htaccess 进行的 CORS 设置。
添加到 api.example.com 上 phps 目录下的 .htaccess 文件(或以上):
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://www.example.com"
Header set Access-Control-Allow-Headers "Origin, Content-Type, X-Auth-Token"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
在 www.example.com,我在 AJAX 调用中添加了 xhrFields: {withCredentials: true}。以下是所有设置:
jQuery.ajax({
url: myURL,
type: "POST",
xhrFields: {withCredentials: true},
dataType: "text",
contentType: "text/xml; charset=\"utf-8\"",
cache: false,
headers: "",
data: myCallJSONStr,
success: function(myResponse) { etc....
URL 调用 api.example.com 上的 php。
请注意 Alexandre 是对的,您必须指定一个确切的子域,不幸的是,任何通配符都不起作用。所以这行不通:
Header set Access-Control-Allow-Origin "*"
使用 Access-Control-Allow-Credentials "true" 设置时,此设置将被 CORS 阻止。
答案 2 :(得分:1)
我后来添加了这篇文章,因为当我需要使用 AJAX 和 PHP 将 cookie 从多个子域传递到单个 API 域时,我遇到了以前的解决方案的问题
这是挑战和解决方案:
1 - api.example.com 上的后端 PHP。
2 - 多个 JS 前端,例如 one.example.com、two.example.com 等
3 - Cookie 需要双向传递。
4 - api.example.com 上从多个前端到 PHP 后端的 AJAX 调用
5 - 在 PHP 中,我不喜欢使用 $_SERVER["HTTP_ORIGIN"],在我看来并不总是可靠/安全(我有一些浏览器的 HTTP-ORIGIN 总是空的)。
在具有单个前端域的 PHP 中执行此操作的正常方法是使用以下内容启动 PHP 代码:
header('Access-Control-Allow-Origin: https://one.example.com');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
在 one.example.com 域上的 JS 中:
jQuery.ajax({
url: myURL,
type: "POST",
xhrFields: {withCredentials: true},
dataType: "text",
contentType: "text/xml; charset=\"utf-8\"",
cache: false,
headers: "",
data: myCallJSONStr,
success: function(myResponse) {.....}
但是,这是行不通的,因为我使用多个子域来调用我的 API 域。
并且此解决方案将不起作用,因为我想传递 cookie:
header('Access-Control-Allow-Origin: *');
与JS站点上的pass on cookie设置冲突:
xhrFields: {withCredentials: true}
这是我所做的:
1 - 使用 GET 参数传递子域。
2 - 在 PHP 中硬编码主域,因此只允许(所有)子域。
这是我的解决方案的 JS/JQuery AJAX 部分:
函数 getSubDomain(){
let mySubDomain = "";
let myDomain = window.location.host;
let myArrayParts = myDomain.split(".");
if (myArrayParts.length == 3){
mySubDomain = myArrayParts[0];
}
return mySubDomain;
}
在 AJAX 调用中:
let mySubDomain = getSubDomain();
if (mySubDomain != ""){
myURL += "?source=" + mySubDomain + "&end"; //use & instead of ? if URL already has GET parameters
}
jQuery.ajax({
url: myURL,
type: "POST",
xhrFields: {withCredentials: true},
dataType: "text",
contentType: "text/xml; charset=\"utf-8\"",
cache: false,
headers: "",
data: myCallJSONStr,
success: function(myResponse) {.....}
最后是 PHP 部分:
<?php
$myDomain = "example.com";
$mySubdomain = "";
if (isset($_GET["source"])) {
$mySubdomain = $_GET["source"].".";
}
$myDomainAllowOrigin = "https://".$mySubdomain.$myDomain;
$myAllowOrigin = "Access-Control-Allow-Origin: ".$myDomainAllowOrigin;
//echo $myAllowOrigin;
header($myAllowOrigin);
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
重要,不要忘记为所有子域设置 cookie,在这种情况下,cookie 的域将是:.example.com(因此在主域前面有一个点):
<?php
//////////////// GLOBALS /////////////////////////////////
$gCookieDomain = ".example.com";
$gCookieValidForDays = 90;
//////////////// COOKIE FUNTIONS /////////////////////////////////
function setAPCookie($myCookieName, $myCookieValue, $myHttponly){
global $gCookieDomain;
global $gCookieValidForDays;
$myExpires = time()+60*60*24*$gCookieValidForDays;
setcookie($myCookieName, $myCookieValue, $myExpires, "/", $gCookieDomain, true, $myHttponly);
return $myExpires;
}
此解决方案允许我从 example.com 上的任何子域调用 api.example.com 上的 API。
注意。对于只有一个调用子域的情况,我更喜欢使用 .htaccess 来设置 CORS 而不是 PHP。下面是一个 .htaccess (linux/apache) 的例子,只有 one.example.com 调用 api.example.com:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://one.example.com"
Header set Access-Control-Allow-Headers "Origin, Content-Type, X-Auth-Token"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
并将这个 .htaccess 放在 api.example.com 的根目录中。