http - razón - no ''access-control-allow-origin'' header is present on the requested resource.
¿Dominios de origen múltiple de control de acceso-permiso-permitir? (26)
¿Hay una manera de permitir múltiples dominios cruzados usando el encabezado Access-Control-Allow-Origin
?
Soy consciente de la *
, pero está demasiado abierta. Tengo muchas ganas de permitir sólo un par de dominios.
Como ejemplo, algo como esto:
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example
He probado el código anterior pero no parece funcionar en Firefox.
¿Es posible especificar múltiples dominios o estoy atrapado con solo uno?
A continuación, le indicamos cómo repetir el encabezado Origin si coincide con su dominio con Nginx, esto es útil si desea servir una fuente de varios subdominios:
location /fonts {
# this will echo back the origin header
if ($http_origin ~ "example.org$") {
add_header "Access-Control-Allow-Origin" $http_origin;
}
}
Aquí hay una opción expandida para apache que incluye algunas de las definiciones de fuentes más recientes y planificadas:
<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>
Aquí hay una solución para la aplicación web Java, basada en la respuesta de yesthatguy.
Estoy usando Jersey REST 1.x
Configure el web.xml para conocer Jersey REST y 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>
Aquí está el código para 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;
}
}
Como se mencionó anteriormente, Access-Control-Allow-Origin
debe ser único y Vary
debe configurarse en Origin
si está detrás de un CDN (Content Delivery Network).
Parte relevante de mi configuración 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'';
}
Ejemplo de código PHP para subdominios coincidentes.
if( preg_match("/http:////(.*?)/.yourdomain.example/", $_SERVER[''HTTP_ORIGIN''], $matches )) {
$theMatch = $matches[0];
header(''Access-Control-Allow-Origin: '' . $theMatch);
}
Esto es lo que hice para una aplicación PHP solicitada por AJAX
$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);
}
Si mi servidor permite el origen de la solicitud, devuelva el $http_origin
como valor del encabezado Access-Control-Allow-Origin
lugar de devolver un *
comodín.
Esto funcionó para mí:
SetEnvIf Origin "^http(s)?://(.+/.)?(domain/.example|domain2/.example)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
Cuando se pone en .htaccess
, funcionará seguro.
HTTP_ORIGIN no es utilizado por todos los navegadores. ¿Qué tan seguro es HTTP_ORIGIN? Para mí viene vacío en FF.
Tengo los sitios a los que permito acceso a mi sitio enviar a través de un ID de sitio, luego verifico mi DB para el registro con ese ID y obtengo el valor de la columna SITE_URL (www.yoursite.com).
header(''Access-Control-Allow-Origin: http://''.$row[''SITE_URL'']);
Incluso si el envío a través de un ID de sitio válido, la solicitud debe ser del dominio que figura en mi base de datos asociada con ese ID de sitio.
Hay una desventaja que debe tener en cuenta: en cuanto salga de los archivos de origen a un CDN (o cualquier otro servidor que no permita secuencias de comandos) o si sus archivos se almacenan en caché en un proxy, se modifica la respuesta en función del "Origen". El encabezado de solicitud no funcionará.
La respuesta de la asistencia de Google sobre la publicación de anuncios a través de SSL y la gramática en la propia RFC parece indicar que puede espaciar las URL delimitadoras. No estoy seguro de qué tan bien está soportado esto en diferentes navegadores.
La respuesta parece ser usar el encabezado más de una vez. Es decir, en lugar de enviar
Access-Control-Allow-Origin: http://domain1.example, http://domain2.example, http://domain3.example
enviar
Access-Control-Allow-Origin: http://domain1.example
Access-Control-Allow-Origin: http://domain2.example
Access-Control-Allow-Origin: http://domain3.example
En Apache, puede hacer esto en una sección httpd.conf
<VirtualHost>
o en un archivo .htaccess
utilizando mod_headers
y esta sintaxis:
Header add Access-Control-Allow-Origin "http://domain1.example"
Header add Access-Control-Allow-Origin "http://domain2.example"
Header add Access-Control-Allow-Origin "http://domain3.example"
El truco es usar add
lugar de append
como primer argumento.
Luché para configurar esto para un dominio que ejecuta HTTPS, así que pensé que compartiría la solución. Usé la siguiente directiva en mi archivo 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>
Cambie example.com
a su nombre de dominio. Agregue esto dentro de <VirtualHost xxxx:xx>
en su archivo httpd.conf . Tenga en cuenta que si su VirtualHost
tiene un sufijo de puerto (por ejemplo :80
), esta directiva no se aplicará a HTTPS, por lo que también deberá ir a / etc / apache2 / sites-available / default-ssl y agregar la misma directiva en ese archivo, dentro de la sección <VirtualHost _default_:443>
.
Una vez que se actualicen los archivos de configuración, deberá ejecutar los siguientes comandos en el terminal:
a2enmod headers
sudo service apache2 reload
Otra solución que estoy usando en 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");
}
Para IIS 7.5+ con el módulo URL Rewrite 2.0 instalado, consulte esta respuesta SO
Para copiar / pegar con bastante facilidad para aplicaciones .NET, escribí esto para habilitar CORS desde un archivo global.asax. Este código sigue el consejo dado en la respuesta actualmente aceptada, reflejando el origen que se da en la solicitud en la respuesta. Esto logra efectivamente ''*'' sin usarlo. La razón de esto es que permite muchas otras funciones de CORS, incluida la capacidad de enviar un AJAX XMLHttpRequest con el atributo ''withCredentials'' establecido en ''true''.
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" , "*");
}
}
Para facilitar el acceso a múltiples dominios para un servicio ASMX, creé esta función en el archivo 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();
}
}
Esto permite el manejo de CORS del verbo OPTIONS
también.
Para múltiples dominios, en su .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>
Para que los usuarios de Nginx permitan CORS para múltiples dominios. Me gusta el ejemplo de @ marshall, aunque sus respuestas solo coinciden con un dominio. Para hacer coincidir una lista de dominios y subdominios, esta expresión regular facilita el trabajo con fuentes:
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";
}
}
Esto solo hará eco de los encabezados "Access-Control-Allow-Origin" que coincidan con la lista dada de dominios.
Parece que la forma recomendada de hacerlo es hacer que su servidor lea el encabezado de origen del cliente, lo compare con la lista de dominios que le gustaría permitir y, si coincide, devuelve el valor del encabezado de Origin
al cliente. como el encabezado Access-Control-Allow-Origin
en la respuesta.
Con .htaccess
puedes hacerlo así:
# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "/.(ttf|otf|eot|woff)$">
<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>
Si intenta tantos ejemplos de código como yo para hacer que funcione con CORS, vale la pena mencionar que primero debe borrar su caché para probar si realmente funciona, similar a problemas como cuando las imágenes antiguas todavía están presentes, incluso si es eliminado en el servidor (porque todavía se guarda en su caché).
Por ejemplo, CTRL + MAYÚS + SUPRIMIENTO en Google Chrome para eliminar su caché.
Esto me ayudó a usar este código después de probar muchas soluciones puras .htaccess
y este parecía el único que funcionaba (al menos para mí):
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>
También tenga en cuenta que está ampliamente difundido que muchas soluciones dicen que tiene que escribir el Header set ...
pero es el Header add ...
Espero que esto ayude a alguien que tiene los mismos problemas durante algunas horas como yo.
Si tiene problemas con las fuentes, use:
<FilesMatch "/.(ttf|ttc|otf|eot|woff)$">
<IfModule mod_headers>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
Tal vez me equivoque, pero por lo que puedo ver, Access-Control-Allow-Origin
tiene una "origin-list"
como parámetro.
Por definición, una origin-list
es:
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
Y a partir de esto, sostengo que se admiten diferentes orígenes y que deben estar separados por espacios .
También podemos configurar esto en el archivo Global.asax para la aplicación Asp.net.
protected void Application_BeginRequest(object sender, EventArgs e)
{
// enable CORS
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");
}
Tuve el mismo problema con woff-fonts, múltiples subdominios tenían que tener acceso. Para permitir subdominios agregué algo como esto a mi 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>
Para múltiples dominios, simplemente puede cambiar la expresión regular en SetEnvIf
.
Un enfoque más flexible es usar las expresiones de Apache 2.4. Puede hacer coincidir contra dominios, rutas y casi cualquier otra variable de solicitud. Aunque la respuesta es *
para todos, los únicos solicitantes que reciben esa respuesta son los que cumplen con los requisitos de todos modos.
<IfModule mod_headers.c>
<If "%{HTTP:Host} =~ ///byourdomain//.example$/i">
Header set Access-Control-Allow-Origin "*"
</If>
</IfModule>
Y una respuesta más en Django. Para tener una vista única, permitir CORS desde múltiples dominios, aquí está mi código:
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