我正在尝试允许访问我网站上的每个子域,以便允许跨子域AJAX调用。有没有办法指定网站的所有子域,例如*.example.com
或者,为什么当我列出了多个域时,以下内容不起作用:
header('Access-Control-Allow-Origin: http://api.example.com http://www.example.com');
我已经阅读了以下问题,这个问题似乎与这个问题相似,如果不是相同的话,除了我想访问子域而这个指的是一般域。
访问控制允许源多个源域?
如果上述问题是此问题的解决方案,那么我如何能够从标头中检索原点。看起来 $_SERVER['HTTP_ORIGIN'] 非常不可靠,甚至不能跨浏览器。我需要能够在任何浏览器中看到源,该浏览器在尝试使用 javascript 发送 AJAX 调用时可能会显示错误。
此问题的解决方案是使用 $_SERVER['HTTP_ORIGIN']
变量来确定请求是否来自允许的域,然后有条件地设置Access-Control-Allow-Origin
,如下所示:
$allowed_domains = [/* Array of allowed domains*/];
if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_domains)) {
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
}
这是我是如何做到的。
Origin
标头由浏览器指定,并将包含在另一个域上请求脚本的域:
Origin: http://www.websiteA.com
因此,您可以在服务器端脚本中将多个域"列入白名单":
$allowedOrigins = [
"http://www.websiteA.com",
"https://www.websiteB.com"
// ... etc
];
然后,您可以检查$_SERVER["HTTP_ORIGIN"]
全局是否包含该白名单中的域:
if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
并将Access-Control-Allow-Origin
响应标头设置为标头值Origin
:
header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
完整脚本:
$allowedOrigins = [
"http://www.websiteA.com",
"https://www.websiteB.com"
// ... etc
];
if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
}
虽然答案有效,但它确实违背了整个事情的目的,因为它允许来自任何主机的请求。
我使用类似的东西:
if(isset($_SERVER['HTTP_ORIGIN'])) {
$origin = $_SERVER['HTTP_ORIGIN'];
if($origin == 'https://sub1.my-website.com' OR $origin == 'https://sub2.my-website.com') {
header("Access-Control-Allow-Origin: $origin");
}
}
如果你想要通配符域,我认为这更有效
if(isset($_SERVER['HTTP_ORIGIN']) && preg_match('!^http(s)?://([a-z0-9-]+.)?example.com$!is', $_SERVER['HTTP_ORIGIN']))
{
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
}
我尝试使用这种方法在特定领域的基础上实现约束:
$allowed_origin = '';
$parts = explode('.', parse_url($_SERVER['HTTP_HOST'])['host']);
if(end($parts).".".prev($parts) === "com.domain") {
$allowed_origin = $_SERVER['HTTP_ORIGIN'];
header('Acesss-Control-Allow-Origin: '. $allowed_origin);
}
我希望它有效。
//Function to be called first in php file.
function CORS_HEADERS_HANDLER(){
if (isset($_SERVER['HTTP_ORIGIN'])){
switch($_SERVER['HTTP_ORIGIN']){
//Handle an IP address and Port
case 'http://1.2.3.4:4200':
header('Access-Control-Allow-Origin: http://1.2.3.4:4200');
break;
//Handle an Website Domain (using https)
case 'https://www.someSite.com':
header('Access-Control-Allow-Origin: https://www.someSite.com');
break;
//Handle an Website Domain (using http)
case 'http://www.someSite.com':
header('Access-Control-Allow-Origin: http://www.someSite.com');
break;
//Catch if someone's site is actually the reject being cheeky
case 'https://not.you':
header('Access-Control-Allow-Origin: https://nice.try');
break;
//Handle a rejection passing something that is not the request origin.
default:
header('Access-Control-Allow-Origin: https://not.you');
break;
}
}else{
header('Access-Control-Allow-Origin: https://not.you');
}
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header('Access-Control-Allow-Credentials: true');
header('Content-Type: application/json; charset=utf-8');
header("Cache-Control: public,max-age=3600");
//if its an options request you don't need to proceed past CORS request.
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
die();
}
}
这是我的挑战和解决方案:
1 - api.example.com 上的后端 PHP。
2 - 多个 JS 前端,如 one.example.com、two.example.com 等。
3 - Cookie 需要双向传递。
4 - 从多个前端到 PHP 后端的 AJAX 调用 api.example.com
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网站上的传递cookie设置冲突:
xhrFields: {withCredentials: true}
这是我所做的:
1 - 使用 GET 参数传递子域。2 - 在PHP中对主域进行硬编码,以便只允许(所有(子域。
这是我的解决方案的 JS/JQuery AJAX 部分:
function 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。以下是仅 one.example.com 调用 api.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 的根目录中。