代码之家  ›  专栏  ›  技术社区  ›  Thomas J Bradley

访问控制允许源多个源域吗?

  •  1347
  • Thomas J Bradley  · 技术社区  · 16 年前

    是否有方法允许使用 Access-Control-Allow-Origin 头球

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

    举个例子,像这样:

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

    我试过上面的代码,但它似乎在Firefox中不起作用。

    可以指定多个域吗,还是我只能指定一个域?

    35 回复  |  直到 7 年前
        1
  •  950
  •   Kristen Grote    7 年前

    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>
    
        2
  •  253
  •   Nikolay Ivanov    7 年前

    我在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");
    }
    
        3
  •  124
  •   Patrick Mevzek James Dean    7 年前

    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 ,它肯定会奏效。

        4
  •  93
  •   the Tin Man    13 年前

    我对劣质字体也有同样的问题,多个子域名必须能够访问。为了允许子域,我在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 .

        5
  •  71
  •   mjallday    13 年前

    如果Origin标头与Nginx匹配,以下是如何回显Origin标头的方法,如果您想为字体提供多个子域,这很有用:

    location /fonts {
        # this will echo back the origin header
        if ($http_origin ~ "example.org$") {
            add_header "Access-Control-Allow-Origin" $http_origin;
        }
    }
    
        6
  •  32
  •   Patrick Mevzek James Dean    7 年前

    对于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();
    });
    
        7
  •  24
  •   eyecatchUp    7 年前

    以下是我为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 header而不是返回a * 通配符。

        8
  •  22
  •   Mark    16 年前

    如上所述, Access-Control-Allow-Origin 应该是独一无二的 Vary 应设置为 Origin

    Nginx配置的相关部分:

    if ($http_origin ~* (https?://.*\.mydomain\.com(:[0-9]+)?)) {
      set $cors "true";
    }
    if ($http_origin ~* (https?://.*\.my-other-domain\.com(:[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';
    }
    
        9
  •  21
  •   Adriano Rosa    11 年前

    有一个缺点你应该知道:一旦你将源文件输出到CDN(或任何其他不允许脚本编写的服务器),或者如果你的文件缓存在代理上,基于“Origin”请求头更改响应将不起作用。

        10
  •  21
  •   Patrick Mevzek James Dean    7 年前

    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”标头。

        11
  •  16
  •   Community Mohan Dere    9 年前

    .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>
    
        12
  •  16
  •   Amruta-Pani hernvnc    7 年前

    对于安装了URL重写2.0模块的IIS 7.5+,请参阅 this SO answer

        13
  •  13
  •   Patrick Mevzek James Dean    7 年前

    这是一个Java web应用程序的解决方案,基于yesthatguy的答案。

    <!-- 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;
        }
    }
    
        14
  •  9
  •   Patrick Mevzek James Dean    7 年前

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

    definition 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
    

    由此,我认为不同的起源是公认的,也应该是 .

        15
  •  8
  •   Alex W    11 年前

    $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');
    
        16
  •  6
  •   noun    12 年前

    文件:

        <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 <VirtualHost _default_:443> 部分。

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

    a2enmod headers
    sudo service apache2 reload
    
        17
  •  5
  •   Liakos    5 年前

    <FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
        <IfModule mod_headers>
            Header set Access-Control-Allow-Origin "*"
        </IfModule>
    </FilesMatch>
    
        18
  •  3
  •   Mike Kormendy    10 年前

    并非所有浏览器都使用HTTP_ORIGIN。 How secure is HTTP_ORIGIN? 对我来说,它在FF中是空的。
    我让我允许访问我的网站的网站通过网站ID发送,然后我检查我的数据库中是否有具有该ID的记录,并获取site_URL列值(www.yoursite.com)。

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

        19
  •  3
  •   QA Collective    6 年前

    <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>
    
        20
  •  2
  •   Community Mohan Dere    9 年前

    global.asax 文件。此代码遵循当前接受的答案中给出的建议,将请求中返回的任何来源反映到响应中。这在不使用它的情况下有效地实现了“*”。

    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" , "*");
        }
    }
    
        21
  •  2
  •   Patrick Mevzek James Dean    7 年前

    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();
        }
    }
    

    这允许CORS处理 OPTIONS

        22
  •  2
  •   Patrick Mevzek James Dean    7 年前

    匹配子域的PHP代码示例。

    if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
            $theMatch = $matches[0];
            header('Access-Control-Allow-Origin: ' . $theMatch);
    }
    
        23
  •  2
  •   timhc22    6 年前
        24
  •  1
  •   Silvain    9 年前

    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
    
        25
  •  1
  •   Akbarali    5 年前

    https://stackoverflow.com/a/7454204/13779574

    if (isset($_SERVER['HTTP_ORIGIN'])) {
       $http_origin = $_SERVER['HTTP_ORIGIN'];
       if ($http_origin == "http://localhost:3000" || $http_origin == "http://api.loc/"){  
          header("Access-Control-Allow-Origin: $http_origin");
       }
    }
    
        26
  •  0
  •   Bob Aman    12 年前

    只能为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
    }
    
        27
  •  0
  •   AlexioVay    9 年前

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

    CTRL+SHIFT+DEL

    这帮助我在尝试了许多纯代码后使用了这段代码 .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 ... 希望这能帮助像我这样几个小时都有同样麻烦的人。

        28
  •  0
  •   sakshi agrawal    7 年前

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

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

    现在只能传递一个s字符串作为源。因此,如果你想在请求中传递多个URL,请将其作为逗号分隔的值传递。

    https://a.hello.com,https://b.hello.com

        29
  •  0
  •   Simon    6 年前

    我也面临着同样的问题。 我的客户端在9097上,api网关在9098上,微服务在上。... 实际上,我使用的是spring cloud Api网关

    在我的微服务中,我也使用了@crossOrigin

    因此浏览器阻止了请求

    我把它解决了--

        @Bean
    public RouteLocator getRL(RouteLocatorBuilder builder) {
        
    return  builder.routes()
        
            .route(p-> 
             "/friendlist","/guest/**"
                    )
             .filters(f ->{
                 //f.removeResponseHeader("Access-Control-Allow-Origin");
                 //f.addResponseHeader("Access-Control-Allow-Origin","http://localhost:9097");
                 f.setResponseHeader("Access-Control-Allow-Origin","http://localhost:9097");
                 return f;
             })
            .uri("lb://OLD-SERVICE")
            
            
        ).build();      
    }
    
        30
  •  0
  •   akhil Raj Kunwar    5 年前

    对于 您可以指定允许的域,例如在CORS中间件中:

    app/Http/Middleware/Cors.php

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\App;
    
    class Cors
    {
        public function handle($request, Closure $next)
        {
            $response = $next($request);
    
            if (!method_exists($response, 'header')) {
                return $response;
            }
    
            $allowedOrigins = [
                'http://localhost:8000',
                'http://localhost:8080',
                'https://app.example.com',
                'https://example.com',
            ];
    
            if (in_array($request->header('origin'), $allowedOrigins)) {
                $origin = $request->header('origin');
            } else {
                return $response;
            }
    
            return $response
                ->header('Access-Control-Allow-Origin', $origin)
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
                ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
                ->header('Access-Control-Max-Age', '86400');
        }
    }
    

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\App;
    
    class Cors
    {
        public function handle($request, Closure $next)
        {
            $response = $next($request);
    
            if (!method_exists($response, 'header')) {
                return $response;
            }
    
            $origin = $request->header('origin');
    
            return $response
                ->header('Access-Control-Allow-Origin', $origin)
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
                ->header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization')
                ->header('Access-Control-Max-Age', '86400');
        }
    }
    

    app/Http/Kernel.php

        protected $routeMiddleware = [
            ...
            'cors' => \App\Http\Middleware\Cors::class,
        ];
        
    

    最后,在任何路线上使用你需要的任何东西:

    Route::group(['middleware' => ['auth', 'cors']], function () {
        ...
        Route::get('/profile', [ProfileController::class, 'index']);
    });