http - Access-Control-Allow-Origin Multiple Origin Domains؟




.htaccess xmlhttprequest (17)

هل هناك طريقة للسماح بالنطاقات المتقاطعة المتعددة باستخدام رأس Access-Control-Allow-Origin؟

أنا على علم * ، لكنه مفتوح جدا. أرغب حقًا في السماح بنطاقين فقط.

على سبيل المثال ، شيء من هذا القبيل:

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

لقد جربت الكود أعلاه ولكن يبدو أنه لا يعمل في Firefox.

هل من الممكن تحديد مجالات متعددة أو هل تمسكت بـ واحد فقط؟


HTTP_ORIGIN غير مستخدم من قبل جميع المتصفحات. ما مدى أمان HTTP_ORIGIN؟ بالنسبة لي فإنه يأتي فارغة في FF.
لديّ المواقع التي أسمح لها بالوصول إلى موقعي عبر إرسال معرّف موقع ، ثم أتحقق من قاعدة البيانات الخاصة بي للسجل الذي يحمل هذا المعرّف واحصل على قيمة العمود SITE_URL (www.yoursite.com).

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

حتى إذا كان الإرسال عبر معرف موقع صالح ، يجب أن يكون الطلب من النطاق المدرج في قاعدة البيانات الخاصة بي المرتبطة بمعرف الموقع هذا.


إذا جربت العديد من الأمثلة البرمجية مثلي لجعلها تعمل باستخدام 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 ... آمل أن يساعد ذلك شخصًا يعاني من نفس المشاكل لبضع ساعات مثلي الآن.


إليك حل لتطبيق Java web ، استنادًا إلى الإجابة من yesthatguy.

أنا أستخدم جيرسي 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.com"};
    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;
}

}

بالنسبة إلى النطاقات المتعددة ، في .htaccess:

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

بالنسبة لمستخدمي 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";
   }
}

سيؤدي هذا إلى ارتداد رؤوس "الوصول - التحكم - السماح - الأصل" التي تتطابق مع قائمة النطاقات المحددة فقط.


تعثرت في إعداد هذا النطاق لنطاق 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 xxxx:xx> في ملف httpd.conf الخاص بك. لاحظ أنه إذا كان VirtualHost يحتوي على لاحقة منفذ (على سبيل المثال :80 ) ، فإن هذا التوجيه لن ينطبق على HTTPS ، لذلك سوف تحتاج أيضًا إلى الانتقال إلى / etc / apache2 / sites-available / default-ssl وإضافة نفس التوجيه في ذلك الملف ، من قسم <VirtualHost _default_:443> .

بمجرد تحديث ملفات التهيئة ، ستحتاج إلى تشغيل الأوامر التالية في المحطة:

a2enmod headers
sudo service apache2 reload

ربما أكون مخطئا .. ولكن بقدر ما أستطيع أن أرى Access-Control-Allow-Origin يحتوي على "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

ومن هذا أنا أزعم أنه يتم قبول أصول مختلفة ويجب فصلها عن الفضاء ...


في ما يلي خيار موسع لـ 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>

كان لي نفس المشكلة مع الخطوط woff ، كان لا بد من الوصول إلى عدة نطاقات فرعية. للسماح للنطاقات الفرعية التي أضفتها بشيء من هذا القبيل إلى 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 .


كما ذكر أعلاه ، يجب أن يكون Access-Control-Allow-Origin فريدًا ويجب تعيين Vary إلى Origin إذا كنت خلف CDN. الجزء ذو الصلة من بلدي Nginx conf:

if ($http_origin ~* (https?://.*\.mydomain.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';
}

للحصول على نسخ / لصق سهل الاستخدام في تطبيقات .NET ، كتبت هذا لتمكين CORS من داخل ملف global.asax. يتبع هذا الرمز النصيحة المقدمة في الإجابة المقبولة حاليًا ، والتي تعكس أي أصل يرد في الطلب في الرد. هذا يحقق بفعالية "*" دون استخدامه. والسبب في ذلك هو أنه يتيح العديد من ميزات CORS الأخرى ، بما في ذلك القدرة على إرسال AJAX XMLHttpRequest مع تعيين سمة 'withCredentials' إلى '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" , "*");
    }
}

مثال على PHP code للمطابقة بين النطاقات الفرعية.

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

هذا ما فعلته لتطبيق PHP الذي طلبته AJAX

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

إذا كان الخادم $http_origin القيمة $http_origin نفسها $http_origin Access-Control-Allow-Origin بدلاً من إرجاع حرف بدل * ،


هناك عيب واحد يجب أن تكون على دراية به: بمجرد أن تقوم بتنزيل الملفات إلى CDN (أو أي خادم آخر لا يسمح بالبرمجة النصية) أو إذا تم تخزين ملفاتك مؤقتًا على الخادم الوكيل ، يتم تبديل الاستجابة بناءً على "الأصل" لن يعمل رأس الطلب.



يبدو أن الإجابة هي استخدام الرأس أكثر من مرة. هذا هو ، بدلا من إرسال

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

إرسال

Access-Control-Allow-Origin: http://domain1.com
Access-Control-Allow-Origin: http://domain2.com
Access-Control-Allow-Origin: http://domain3.com

على Apache ، يمكنك القيام بذلك في ملف httpd.conf <VirtualHost> أو .htaccess باستخدام mod_headers وبناء الجملة هذا:

Header add Access-Control-Allow-Origin "http://domain1.com"
Header add Access-Control-Allow-Origin "http://domain2.com"
Header add Access-Control-Allow-Origin "http://domain3.com"

الحيلة هي استخدام add بدلاً من append كوسيطة الأولى.


يمكننا أيضًا تعيين هذا في ملف Global.asax لتطبيق Asp.net.

protected void Application_BeginRequest(object sender, EventArgs e)
    {

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

    }




cross-domain