17

我在 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 上设置了一个 cookie,在 api.exemple.com 上设置了另一个。Cookie 仅使用 Domain=.exemple.com 设置。没有路径,没有 HTTPOnly。

注意:最后我只需要 api.exemple.com 上的一个。但这些是为了测试。

使用我的浏览器 (Firefox 16) 直接查询可以正常工作。api上查询:设置并发送了两个cookie。在 www 上查询:cookie 已设置,api 中的两个也已发送。(当然,前提是我在 api 之后查询 www)。

现在,我清理浏览器 cookie 并仅查询 www。查询 www: 工作正常,和以前一样。来自 www 的 ajax 请求的 api 子查询:不发送 cookie。Set-Cookies 什么都不做。使用 Firebug,我在响应中看到了 cookie。但在后续请求或页面信息中没有它们的痕迹。

我试图在 Firefox 上启用 cookie 日志。绝对没有来自 api 的 cookie 的痕迹,甚至没有拒绝通知。

最后,我只需要一种在 api 上存储一个 cookie 的方法。为此,我很开放:)

信息:两台服务器都是NodeJS。我尝试在服务器端(Set-Cookie 标头)、客户端(document.cookies)上手动使用 firebug 设置 cookie。

我检查过的其他帖子没有解决方案(还有很多我不记得的帖子):

使用 javascript 设置跨子域 cookie

Cookie 和子域

subdomain.example.com 可以设置一个可以被example.com读取的cookie吗?

4

3 回答 3

47

在 api 上设置允许凭据标头

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

http://api.jquery.com/jQuery.ajax/

于 2012-10-22T06:57:51.963 回答
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 将阻止此设置。

于 2021-02-11T04:35:14.907 回答
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。这是一个仅用于调用 api.example.com 的 one.example.com 的 .htaccess (linux/apache) 示例:

<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 的根目录中。

于 2021-02-12T00:11:42.100 回答