访问控制允许原始多个域?


1049

有没有一种方法可以使用Access-Control-Allow-Origin标头允许多个跨域?

我知道*,但是它太开放了。我真的只想允许几个域名。

例如,如下所示:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

我已经尝试了上面的代码,但是它似乎在Firefox中不起作用。

是否可以指定多个域,还是我只能使用一个?



3
使用最新的Firefox,逗号分隔的域名和空格分隔的域名都无法正常工作。与域列表匹配并将单个主机放在标头中仍然可以提高安全性,并且可以正常工作。
丹尼尔W.14年

1
如果您在使用HTTPS时遇到麻烦,我找到了一个解决方案
Alex W

7
重要说明Access-Control-Allow-Origin标头中仅允许使用cretain域并不意味着其他域无法触发此端点上的方法(例如REST API方法)。这只是意味着不允许的来源不能在javascript中使用结果(浏览器确保了这一点)。为了限制对特定域的端点的访问,请使用服务器端请求过滤器,例如,对于不允许的域返回HTTP 401。
klues

1
Vary: Origin当您要使用多个URL时,应始终附加标头,请参阅:fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null,

Answers:


861

听起来,推荐的方法是让服务器从客户端读取Origin标头,将其与您希望允许的域列表进行比较,如果匹配,则将Origin标头的值回显给客户端Access-Control-Allow-Origin响应中的标题。

随着.htaccess你可以做到这一点:

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>


153
我对这个答案的问题是,它实际上并没有帮助我,因为我们使用CDN,而且显然我们无法控制CDN如何以编程方式设置标头。
英国电信

6
-在我的回答如下实际例子(Nginx的)stackoverflow.com/a/12414239/6084
mjallday

71
如果需要考虑缓存或CDN,请使用Vary标头来告诉缓存/ CDN为不同的Origin请求标头值保留单独的响应。您的响应中将包含诸如“ Vary:Origin”之类的标题。然后,缓存/ CDN知道应该发送对标头为“ Origin:foo.example.com ” 的请求的一个响应,以及对标头为“ Origin:bar.example.com ” 的请求的不同响应。
肖恩

10
@saturdayplace,如果您有权访问Origin标头,则表示您已经过去了CORS。
Paul Draper

222

我在PHP中使用的另一个解决方案:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

12
为什么不使用stackoverflow.com/a/1850482/11635中建议的方法[并且不发送通配符,仅发送请求的来源]?这只是宽容而没有取得更多成就吗?
Ruben Bartelink

15
header('Access-Control-Allow-Origin: *')有时说,如果证书标志为真不能使用通配符-当发生header('Access-Control-Allow-Credentials: true')可能。因此,$http_origin如果条件满足,最好允许其本身
Rakib 2012年

6
替换最后一行header("Access-Control-Allow-Origin: " . $http_origin);,使其工作
弗朗索瓦·罗曼

2
该代码似乎有缺陷,因为如果未识别到HTTP_ORIGIN标头,则根本不会设置Access-Control-Allow-Origin,从而使脚本处于打开状态。
Stephen R

9
@StephenR实际上“完全关闭”会更准确,因为这样做的目的是将脚本打开到其他域;)
Kaddath

113

这为我工作:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

当放入时.htaccess,它将肯定起作用。


24
最适合我的解决方案,但我增加了端口支持(例如,开发时使用localhost:3000):SetEnvIf Origin“ ^ http(s)?://(。+ \。)?(localhost | stackoverflow.com | example1.com)( :[0-9] +)?$“ origin_is = $ 0
vszurma

2
在所有关于stackoverflow的答案中,这是行之有效的。
Meetai.com 2015年

我需要为此添加Header set Access-Control-Allow-Credentials true才能像@George的答案一样工作
-99个问题-语法不是

当我使用Origin时,这可以肯定地工作。但是在某些情况下,Origin在某些请求中不可用,它也特定于浏览器。然后,我决定使用Referer代替Origin。使用RefererWorks,但问题是将完整URL设置回Access-Control-Allow-Origin我想从中删除域名Referer并将其分配给Access-Control-Allow-Origin。类似于此echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3in-bash命令的结果。在(apache)conf文件中可以这样做吗?任何的想法?
3AK

1
这对我不起作用。当我添加两行时,总是出现代码500错误。实际使用PHP 5.6.15
BoCyrill '16

91

我对woff-fonts有同样的问题,多个子域必须具有访问权限。为了允许子域,我在httpd.conf中添加了以下内容:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

对于多个域,您只需更改中的正则表达式即可SetEnvIf


4
做到了。只要确保您正确调整了正则表达式即可。我需要添加一个问号以允许域本身,例如(.*\.?example\.org)for example.comsub.example.com
trkoch 2012年

3
关于如何针对IIS 7进行调整的任何想法?
2013年

那不是达到目的吗?什么能防止恶意用户伪造Origin标头值?
格雷戈里·约瑟夫

1
@GrégoryJosephAccess-Control-Allow-Origin并不是要向可以请求资源的人隐藏资源。这是关于防止恶意网站让最终用户呼叫您的网站。对于字体文件,这只能有效地限制字体的热链接,为什么它们(mozilla / firefox)对其他资源(js,css等)不做同样的工作超出了我的范围。
Tracker1

@trkoch,您的正则表达式中有一个错误,它也会允许subexample.com。您应该将其更改为:((.*\.)?example\.org)
bluesmoon 2015年

65

如果它与Nginx匹配您的域,请按照以下方法回显Origin头,如果您想为一个字体提供多个子域,这将很有用:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

无法理解这与以下内容有何不同:add_header Access-Control-Allow-Origin *; 介意解释吗?
Anoyz 2015年

这将返回一个标头,该标头授权浏览器仅发送来自指定域的请求。如果我猜想我会说浏览器可以授权该页面上加载的另一个域中的内容访问服务器。
mjallday'2

7
@Anoyz的一件事可能是增强了安全性,其中不允许使用“允许*”,但是允许标题的指定且匹配的主机名有效。例如,如果您要跨域发送授权信息,则不能使用“允许*”
TCC 2015年

3
.在example.org解释为,因为这是一个正则表达式什么价值?在哪种情况下,这会错误地允许使用自定义示例组织TLD吗?
stickj

1
正确的正则表达式应该是"^example\.org$"因为您需要确保黑客无法使用subdomainexample.org(use ^)或example.orgevil(use $)或examplezorg(escape \.)来
跳过

27

这是我为AJAX请求的PHP应用程序所做的工作

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

如果我的服务器允许发出请求的来源,请返回$http_origin自身作为Access-Control-Allow-Origin标头的值,而不是返回*通配符。


20

您应该意识到一个缺点:一旦将文件外包给CDN(或任何其他不允许脚本的服务器),或者文件缓存在代理服务器上,就会基于“来源”更改响应请求标头将不起作用。


4
您能详细说明一下,还是将我们指向可以寻找更多信息的地方?我希望使用Limelight做到这一点,希望您错了。我们的一位技术运营人员表示,只要我们的CDN种子服务器发送标头,CDN本身就会发送标头。尚未测试
-BT

12
如果需要考虑缓存或CDN,请使用Vary标头来告诉缓存/ CDN为不同的Origin请求标头值保留单独的响应。您的响应中将包含诸如“ Vary:Origin”之类的标题。然后,缓存/ CDN知道应该发送对标头为“ Origin:foo.example.com ” 的请求的一个响应,以及对标头为“ Origin:bar.example.com ” 的请求的不同响应。
肖恩

Vary: Origin 没有最大的CDN之一Akamai的支持 ... 这里
Brad Parks

20

对于多个域,在您的中.htaccess

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>

4
此代码段非常适合我。但我不明白它的作用:D
卡尔·阿德勒

2
这对我
有用

它与stackoverflow.com/a/14034228/209139几乎相同。仅仅是.htaccess语法比PHP难读得多。Header set Vary Origin将是此答案的一个不错的补充。
TRiG 2015年

1
非常感谢您的帮助
Cool Perfectionist

2
我不得不AccessControlAllowOrigin=$0$1改为AccessControlAllowOrigin=$0。否则,它不适用于HTTPS来源。http://example.com正确地https://example.com列出来了,但最终以形式出现了https://example.coms,最后还有一个附加s内容。
TRiG

17

对于Nginx用户,允许多个域的CORS。我喜欢@marshall的示例,尽管他的答案仅匹配一个域。为了匹配域和子域的列表,此正则表达式使使用字体更加容易:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

这只会回显与给定域列表匹配的“ Access-Control-Allow-Origin”标头。


认为您需要在\ z结尾处锁定该正则表达式,因为否则将允许domain3.com.badhacker.com访问。
dft17年

@dft我们在结尾处定义$,以实现此目的
Adriano Rosa

抱歉,我的意思是要点,@ AdrianoRosa的实际帖子与\ z
dft


13

这是基于yesthatguy的答案的Java Web应用程序解决方案。

我正在使用Jersey REST 1.x

配置web.xml以了解Jersey REST和CORSResponseFilter

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

这是CORSResponseFilter的代码

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}

上述链接已过期,您可以添加一个新链接,还是可以使用更多详细信息更新答案,谢谢
RajKumar Samala

我添加了更多详细信息,希望这会
有所

12

正如上面提到的,Access-Control-Allow-Origin应该是唯一的,Vary应设置为Origin,如果你是一个CDN(内容分发网络)的后面。

我的Nginx配置的相关部分:

if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}

具有set $cors某种隐藏的含义,还是仅针对您的配置?似乎可以与第二个一起省略if
mikezter 17-4-26

没错,如果这是您测试设置标头的唯一条件,则可以省略,因为我的配置中有多个。
hernvnc

9

也许我错了,但据我所知Access-Control-Allow-Origin有一个"origin-list"as参数。

根据定义origin-list是:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

因此,我认为可以接受不同的来历,并且应将它们分开


2
这似乎是对规范的正确解释。也就是说,当前的浏览器似乎未完全支持该规范(例如,我刚刚在Firefox 17.0上对其进行了测试,并确认它将无法正常工作)。
里克·里恩切

7
所述CORS规范5.1 Access-Control-Allow-Origin Response Header指出原点列表被约束:而不是让起源的空间分隔的列表,它是一个单一的原点或字符串“空”。
maxpolk

2
正如我在对自己的答案的评论中提到的那样,这是实现者注意的一部分,而不是RFC 2119要求。正确的答案绝对是使用空格分隔的值。问题仅在于实现不完整,因此“正确”的答案不一定奏效。应该,但不是。但是,将来,随着实现的改善,这种情况可能会改变。
鲍勃·阿曼

8

对于ExpressJS应用程序,您可以使用:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

这将允许所有其他呼叫通过下一个呼叫...
Ievgen Naida

@IevgenNaida那么?怎么了
eyecatchUp

7

我努力将其设置为运行HTTPS的域,所以我想我会分享解决方案。我在httpd.conf文件中使用了以下指令:

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

更改example.com为您的域名。将此添加<VirtualHost x.x.x.x:xx>到您的httpd.conf文件中。请注意,如果您VirtualHost有端口后缀(例如:80),那么此指令将不适用于HTTPS,因此您还需要转到/ etc / apache2 / sites-available / default-ssl并在该文件的内部添加相同的指令的<VirtualHost _default_:443>部分。

配置文件更新后,您将需要在终端中运行以下命令:

a2enmod headers
sudo service apache2 reload

我喜欢此选项,并将其与@George具有的实现组合/修改。有时服务器没有可用的a2enmod,因此您要做的就是检查主httpd.conf,以查看是否未注释行:LoadModule headers_module modules / mod_headers.so。
Mike Kormendy 2015年

我的来源有一个端口号,因此我修改了正则表达式以使其包含: ^http(s)?://(.+\.)?example\.com(:\d+)?$
indiv

5

如果您在字体方面遇到麻烦,请使用:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

3

一种更灵活的方法是使用Apache 2.4的表达式。您可以匹配域,路径以及几乎所有其他请求变量。尽管发送的响应始终是*,但接收响应的唯一请求者仍然是满足要求的请求者。Origin在表达式中使用(或任何其他)请求标头会导致Apache自动将其合并到Vary响应标头中,从而不会将响应重用于其他来源。

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

2
我之所以来到这里,是因为某些浏览器不接受“ *登录”之类的凭据。因此,如果传递匹配的主机名而不是会更好*
KeitelDOG

@KeitelDOG如何动态捕获正确的来源并在有多个来源的情况下将其发送回去,而不是为每个域重复代码?看起来表达式可能是可行的,但是文档对我来说还不清楚。
Walf

实际上,我真正的问题是因为laravel没有返回预检请求的Access-Control-Allow-Origin标头,该标头OPTIONS检查标头以查看服务器是否允许此来源。我把它修好了。所以*对我来说不是真正的问题。但是,仍然有一些浏览器不接受*与凭证,因此,当一个Web应用程序在发送跨来源要求,他们必须指定HTTP_ORIGIN标题,你可能有变量动态访问Origin.htaccess针对Apache,或者$_SERVER['HTTP_ORIGIN'];在PHP。无论如何,您的解决方案是好的,因为它允许所有来源,但安全性较低
KeitelDOG

但是要记住的两件事是:1)提供*允许一切。2)HOST与ORIGIN不同。主机是传递给请求标头的实际“目标主机”。但是ORIGIN是INITIAL HOST将请求发送到的TARGET HOST。因此,在您的代码中,它ORIGIN HOST被忽略并且从不使用。查看上面的答案,您将看到它们如何使用ORIGIN值将其添加到中Access-Control-Allow-Origin
KeitelDOG

@KeitelDOG *不允许所有人,因为Origin在表达式中使用请求标头会导致Apache自动将其合并到Vary响应标头中,除非有人使用req_novary('Origin')(可能不希望这样做)。浏览器知道对于不同的内容,他们可能会得到不同的响应Origin,如果发送的值未通过测试,Access-Control-Allow-Origin则永远不会设置标头。
沃尔夫,

2

并非所有浏览器都使用HTTP_ORIGIN。 HTTP_ORIGIN的安全性如何?对我来说,它在FF中是空的。
我有允许访问我的站点的站点通过站点ID发送,然后检查数据库中具有该ID的记录并获得SITE_URL列值(www.yoursite.com)。

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

即使通过有效的站点ID发送,该请求也必须来自与该站点ID关联的数据库中列出的域。


2

这是针对Apache的扩展选项,其中包括一些最新的和计划的字体定义:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

2

为了促进ASMX服务的多域访问,我在global.asax文件中创建了以下功能:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

这也允许对OPTIONS动词进行CORS处理。


2

匹配子域的PHP代码示例。

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

2

为了对.NET应用程序进行相当简单的复制/粘贴,我编写了此代码以从global.asax文件中启用CORS 。该代码遵循当前接受的答案中给出的建议,将请求中给出的任何原点返回到响应中。这有效地实现了“ *”而不使用它。

这样做的原因是,它启用了多个其他CORS功能,包括发送“ withCredentials”属性设置为“ true”的AJAX XMLHttpRequest的功能。

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}

2

PHP代码:

$httpOrigin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : null;
if (in_array($httpOrigin, [
    'http://localhost:9000', // Co-worker dev-server
    'http://127.0.0.1:9001', // My dev-server
])) header("Access-Control-Allow-Origin: ${httpOrigin}");
header('Access-Control-Allow-Credentials: true');

1

在Django中还有一个答案。为了有一个视图,允许来自多个域的CORS,这是我的代码:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response

1

AWS Lambda / API网关

有关如何在无服务器AWS Lambda和API网关上配置多个来源的信息-尽管对于一个人来说相当大的解决方案应该很简单-请参见此处:

https://stackoverflow.com/a/41708323/1624933


当前无法在API Gateway中配置多个来源,请参见此处:https : //docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html),但建议(参见上面的答案)是:

  • 检查浏览器发送的Origin标头
  • 对照来源白名单进行检查
  • 如果匹配,则返回传入的Origin作为Access-Control-Allow-Origin标头,否则返回一个占位符(默认origin)。

简单的解决方案显然是启用ALL(*),如下所示:

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
        },
        body: JSON.stringify([{

但最好在API网关端执行此操作(请参见上面的第二个链接)。


2
Access-Control-Allow-Credentials: true不允许使用通配符Access-Control-Allow-Origin: *。设置一个特定的<origin>代替。
汤姆

@Tom,是的,不知道为什么会在那里,我不记得了,但是我可能已经从AWS上添加的默认值复制了它?感谢您指出这一点。
timhc22

0

Google关于通过SSL投放广告RFC本身语法的支持答案似乎表明您可以用空格分隔URL。不确定在不同的浏览器中对此的支持程度如何。


“通过ssl投放广告”链接到规范w3.org/TR/cors/#access-control-allow-origin-response-header,其中添加了一个注释:“实际上,产地列表或空产品的生产受到更多限制。而不是让起源的空间分隔的列表,它是一个单一的原点或字符串“空”。
spazm

注意这一点很重要,但是当规范说“在实践中”时,这并不意味着这样做是有效的。这意味着如果以这种方式进行操作,则可能会遇到问题,因为大多数实施者都错误地或不完全地执行了规范。该规范确实允许使用空格分隔的起源列表,您可以在EBNF中的以下位置看到该列表origin-listtools.ietf.org/html/rfc6454#section-7.1
Bob Aman

0

如果您尝试了许多像我这样的代码示例,以使其可以使用CORS进行工作,那么值得一提的是,您必须先清除缓存才能尝试它是否真正起作用,这类似于像仍然存在旧图像的问题,即使它仍然存在。在服务器上删除(因为它仍保存在缓存中)。

例如CTRL + SHIFT + DEL在Google Chrome浏览器中删除您的缓存。

这在尝试了许多纯.htaccess解决方案之后帮助我使用了这段代码,这似乎是唯一可行的方法(至少对我而言):

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

另请注意,许多解决方案都说您必须键入,Header set ...但它已经广泛传播Header add ...。希望这可以像我一样帮助几个小时来遇到同样麻烦的人。


0

下面的答案特定于C#,但该概念应适用于所有不同的平台。

要允许来自Web API的跨源请求,您需要允许对您的应用程序的Option请求,并在控制器级别添加以下注释。

[EnableCors(UrlString,Header,Method)]现在,原点只能以字符串形式传递。因此,如果您想在请求中传递多个URL,则将其作为逗号分隔值传递。

UrlString =“ https://a.hello.com,https://b.hello.com


0

Access-Control-Allow-Origin标头只能指定一个原点。但是您可以根据要求在响应中设置原点。同样不要忘记设置Vary标头。在PHP中,我将执行以下操作:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

-2

我们也可以在Asp.net应用程序的Global.asax文件中进行设置。

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.