Access-control-allow-origin ที่มีหลายโดเมน


102

ใน web.config ของฉันฉันต้องการระบุโดเมนมากกว่าหนึ่งโดเมนสำหรับaccess-control-allow-originคำสั่ง ฉันไม่ต้องการใช้*. ฉันได้ลองใช้ไวยากรณ์นี้แล้ว:

<add name="Access-Control-Allow-Origin" value="http://localhost:1506, http://localhost:1502" />

อันนี้

<add name="Access-Control-Allow-Origin" value="http://localhost:1506 http://localhost:1502" />

อันนี้

<add name="Access-Control-Allow-Origin" value="http://localhost:1506; http://localhost:1502" />

และอันนี้

<add name="Access-Control-Allow-Origin" value="http://localhost:1506" />
<add name="Access-Control-Allow-Origin" value="http://localhost:1502" />

แต่ไม่มีสิ่งใดได้ผล ไวยากรณ์ที่ถูกต้องคืออะไร?

คำตอบ:


80

สามารถมีAccess-Control-Allow-Originส่วนหัวการตอบกลับได้เพียงรายการเดียวและส่วนหัวนั้นสามารถมีค่าต้นทางได้เพียงค่าเดียว ดังนั้นเพื่อให้สิ่งนี้ใช้งานได้คุณต้องมีรหัสที่:

  1. คว้าOriginส่วนหัวของคำขอ
  2. ตรวจสอบว่าค่าต้นทางเป็นหนึ่งในค่าที่อนุญาตพิเศษหรือไม่
  3. หากถูกต้องให้ตั้งค่าAccess-Control-Allow-Originส่วนหัวด้วยค่านั้น

ฉันไม่คิดว่าจะมีวิธีใดทำได้ผ่านทาง web.config เท่านั้น

if (ValidateRequest()) {
    Response.Headers.Remove("Access-Control-Allow-Origin");
    Response.AddHeader("Access-Control-Allow-Origin", Request.UrlReferrer.GetLeftPart(UriPartial.Authority));

    Response.Headers.Remove("Access-Control-Allow-Credentials");
    Response.AddHeader("Access-Control-Allow-Credentials", "true");

    Response.Headers.Remove("Access-Control-Allow-Methods");
    Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
}

2
นั่นตอบคำถามของฉัน ฉันไม่แน่ใจว่าทำไม Microsoft ไม่อนุญาตให้ระบุแหล่งที่มาหลายรายการใน web.config แม้ว่า ....
แซม

17
ฉันจะเพิ่มรหัสนี้ได้ที่ไหน? ฉันมีไฟล์ข้อความธรรมดาที่สร้างโดยเซิร์ฟเวอร์และอ่านผ่าน AJAX ไม่มีรหัสเลย ฉันจะใส่รหัสเพื่อ จำกัด การเข้าถึงไฟล์ข้อความในไดเร็กทอรีของฉันได้ที่ไหน?
Harry

3
@Simon_Weaver มี*ค่าที่อนุญาตให้ต้นกำเนิดใด ๆ เข้าถึงทรัพยากรได้ อย่างไรก็ตามคำถามเดิมคือถามเกี่ยวกับการอนุญาตพิเศษชุดของโดเมน
monsur

2
เนื่องจากฉันยังใหม่กับ asp. net ฉันสามารถถามได้ว่าจะใส่รหัสนี้ในโปรเจ็กต์ asp .net web api ได้ที่ไหน
อมฤต

96

สำหรับ IIS 7.5+ และ Rewrite 2.0 คุณสามารถใช้:

<system.webServer>
   <httpProtocol>
     <customHeaders>
         <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
         <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
     </customHeaders>
   </httpProtocol>
        <rewrite>            
            <outboundRules>
                <clear />                
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?domain1\.com|(.+\.)?domain2\.com|(.+\.)?domain3\.com))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>           
            </outboundRules>
        </rewrite>
 </system.webServer>

อธิบายRESPONSE_Access_Control_Allow_Originส่วนตัวแปรของเซิร์ฟเวอร์:
ใน Rewrite คุณสามารถใช้สตริงใดก็ได้หลังจากนั้นRESPONSE_และจะสร้างส่วนหัวการตอบกลับโดยใช้คำที่เหลือเป็นชื่อส่วนหัว (ในกรณีนี้คือ Access-Control-Allow-Origin) Rewrite ใช้ขีดล่าง "_" แทนเครื่องหมายขีดกลาง "-" (การเขียนซ้ำจะแปลงเป็นขีดกลาง)

การอธิบายตัวแปรเซิร์ฟเวอร์HTTP_ORIGIN:
ในทำนองเดียวกันใน Rewrite คุณสามารถคว้าส่วนหัวของคำขอใดก็ได้โดยใช้HTTP_เป็นคำนำหน้า กฎเดียวกันกับเครื่องหมายขีดกลาง (ใช้เครื่องหมายขีดล่าง "_" แทนเครื่องหมายขีดกลาง "-")


คุณนึกถึงเหตุผลใดบ้างที่ทำให้ไม่สามารถใช้กับ IIS 7.5 ได้
Phil Ricketts

ผมว่าน่าจะใช้ได้ ฉันระบุเวอร์ชัน IIS 8.5 เนื่องจากเป็นที่ที่ฉันทดสอบ
Paco Zarate

4
@PacoZarate ดีหนึ่งเคล็ดลับที่ดี เพื่อให้ง่ายต่อการ regex และทำให้มันทั่วไปมากขึ้นคุณสามารถใช้ (http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net)))- ด้วยวิธีนี้คุณสามารถเพิ่มโดเมนอื่น ๆ ได้ค่อนข้างง่ายและรองรับโดเมนระดับบนสุดหลายโดเมน (เช่น com, org, net เป็นต้น)
Merlin

4
เพิ่งลองสิ่งนี้ใน IIS 7.5 ดูเหมือนว่าจะทำงานได้ดี
Prescient

2
มีปัญหากับการแคช? หลังจากปรับแต่ง web.config แล้วเว็บไซต์แรกที่ฉันไปถึงจะเข้ากันได้ดี แต่เว็บไซต์ที่สองส่งกลับส่วนหัวเดียวกันกับเว็บไซต์แรก จึงทำให้โดเมนไม่ตรงกันเกินไป.
แอร์

21

ใน Web.APIสามารถเพิ่มแอตทริบิวต์นี้ได้Microsoft.AspNet.WebApi.Corsตามรายละเอียดที่http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

ใน MVCคุณสามารถสร้างแอตทริบิวต์ตัวกรองเพื่อทำงานนี้ให้กับคุณ:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = true, Inherited = true)]
public class EnableCorsAttribute : FilterAttribute, IActionFilter {
    private const string IncomingOriginHeader = "Origin";
    private const string OutgoingOriginHeader = "Access-Control-Allow-Origin";
    private const string OutgoingMethodsHeader = "Access-Control-Allow-Methods";
    private const string OutgoingAgeHeader = "Access-Control-Max-Age";

    public void OnActionExecuted(ActionExecutedContext filterContext) {
        // Do nothing
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var isLocal = filterContext.HttpContext.Request.IsLocal;
        var originHeader = 
             filterContext.HttpContext.Request.Headers.Get(IncomingOriginHeader);
        var response = filterContext.HttpContext.Response;

        if (!String.IsNullOrWhiteSpace(originHeader) &&
            (isLocal || IsAllowedOrigin(originHeader))) {
            response.AddHeader(OutgoingOriginHeader, originHeader);
            response.AddHeader(OutgoingMethodsHeader, "GET,POST,OPTIONS");
            response.AddHeader(OutgoingAgeHeader, "3600");
        }
    }

    protected bool IsAllowedOrigin(string origin) {
        // ** replace with your own logic to check the origin header
        return true;
    }
}

จากนั้นเปิดใช้งานสำหรับการกระทำ / ตัวควบคุมเฉพาะ:

[EnableCors]
public class SecurityController : Controller {
    // *snip*
    [EnableCors]
    public ActionResult SignIn(Guid key, string email, string password) {

หรือเพิ่มสำหรับคอนโทรลเลอร์ทั้งหมดใน Global.asax.cs

protected void Application_Start() {
    // *Snip* any existing code

    // Register global filter
    GlobalFilters.Filters.Add(new EnableCorsAttribute());
    RegisterGlobalFilters(GlobalFilters.Filters);

    // *snip* existing code
}

คุณรู้หรือไม่ว่า. Net / MVC ใช้งานได้กับเวอร์ชันใด
Keab42

ฉันใช้สิ่งนี้สำเร็จแล้วใน. net 4 / MVC 3 - เท่าที่ฉันทราบว่าควรใช้งานได้ในเวอร์ชันที่สูงกว่า แต่อาจมีวิธีที่ดีกว่าในการลงทะเบียนตัวกรองส่วนกลางใน MVC เวอร์ชันหลัง ๆ
Rob Church

โปรดทราบว่าโซลูชัน WEB API 2 เท่านั้น ไม่ใช่สำหรับ WEB API 1.
Samih A

5

หลังจากอ่านทุกคำตอบและลองใช้แล้วไม่มีข้อใดช่วยฉันเลย สิ่งที่ฉันพบในขณะค้นหาที่อื่นคือคุณสามารถสร้างแอตทริบิวต์ที่กำหนดเองซึ่งคุณสามารถเพิ่มลงในคอนโทรลเลอร์ได้ จะเขียนทับ EnableCors และเพิ่มโดเมนที่อนุญาตพิเศษในนั้น

โซลูชันนี้ใช้งานได้ดีเพราะช่วยให้คุณมีโดเมนที่อนุญาตพิเศษใน webconfig (appsettings) แทนการเข้ารหัสในแอตทริบิวต์ EnableCors บนคอนโทรลเลอร์ของคุณ

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsByAppSettingAttribute : Attribute, ICorsPolicyProvider
{
    const string defaultKey = "whiteListDomainCors";
    private readonly string rawOrigins;
    private CorsPolicy corsPolicy;

    /// <summary>
    /// By default uses "cors:AllowedOrigins" AppSetting key
    /// </summary>
    public EnableCorsByAppSettingAttribute()
        : this(defaultKey) // Use default AppSetting key
    {
    }

    /// <summary>
    /// Enables Cross Origin
    /// </summary>
    /// <param name="appSettingKey">AppSetting key that defines valid origins</param>
    public EnableCorsByAppSettingAttribute(string appSettingKey)
    {
        // Collect comma separated origins
        this.rawOrigins = AppSettings.whiteListDomainCors;
        this.BuildCorsPolicy();
    }

    /// <summary>
    /// Build Cors policy
    /// </summary>
    private void BuildCorsPolicy()
    {
        bool allowAnyHeader = String.IsNullOrEmpty(this.Headers) || this.Headers == "*";
        bool allowAnyMethod = String.IsNullOrEmpty(this.Methods) || this.Methods == "*";

        this.corsPolicy = new CorsPolicy
        {
            AllowAnyHeader = allowAnyHeader,
            AllowAnyMethod = allowAnyMethod,
        };

        // Add origins from app setting value
        this.corsPolicy.Origins.AddCommaSeperatedValues(this.rawOrigins);
        this.corsPolicy.Headers.AddCommaSeperatedValues(this.Headers);
        this.corsPolicy.Methods.AddCommaSeperatedValues(this.Methods);
    }

    public string Headers { get; set; }
    public string Methods { get; set; }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,
                                               CancellationToken cancellationToken)
    {
        return Task.FromResult(this.corsPolicy);
    }
}

    internal static class CollectionExtensions
{
    public static void AddCommaSeperatedValues(this ICollection<string> current, string raw)
    {
        if (current == null)
        {
            return;
        }

        var paths = new List<string>(AppSettings.whiteListDomainCors.Split(new char[] { ',' }));
        foreach (var value in paths)
        {
            current.Add(value);
        }
    }
}

ฉันพบคู่มือนี้ทางออนไลน์และมันใช้งานได้ดี:

http://jnye.co/Posts/2032/dynamic-cors-origins-from-appsettings-using-web-api-2-2-cross-origin-support

ฉันคิดว่าจะทิ้งที่นี่เพื่อใครก็ตามที่ต้องการ


นี่คือคำตอบแบบลิงก์เท่านั้น โปรดให้คำตอบเป็นของตัวเองแทน
Unslander Monica

1
ตกลงฉันใหม่ที่นี่เป็นแบบนี้มากกว่าที่ควรจะเป็น ??
Helpha

3

ฉันจัดการเพื่อแก้ปัญหานี้ในรหัสการจัดการคำขอตามคำแนะนำจาก 'monsur'

string origin = WebOperationContext.Current.IncomingRequest.Headers.Get("Origin");

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);

นั่นคือวิธีการทำในเว็บฟอร์ม เพียงใช้คำขอส่วนหัวเมื่อมี และหากจำเป็นให้ใช้รายการที่อนุญาตพิเศษเพื่อกรองโดเมนที่อนุญาตเท่านั้น
หลัง

3
ซึ่งดีพอ ๆ กับการเพิ่ม <add name = "Access-Control-Allow-Origin" value = "*" /> ในไฟล์ web.config
Isaiah4110

3

สำหรับ IIS 7.5+ คุณสามารถใช้ IIS CORS Module: https://www.iis.net/downloads/microsoft/iis-cors-module

web.config ของคุณควรเป็นดังนี้:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://localhost:1506">
                <allowMethods>                    
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
            <add origin="http://localhost:1502">
                <allowMethods>
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
        </cors>
    </system.webServer>
</configuration>

คุณสามารถค้นหาข้อมูลอ้างอิงการกำหนดค่าได้ที่นี่: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference


หากได้ผลอย่างที่บอกฉันหวังว่าคุณจะโพสต์เมื่อ 3 ปีที่แล้ว! โว้ว!
Michael

2

ดูในไลบรารี Thinktecture IdentityModel - มีการสนับสนุน CORS เต็มรูปแบบ:

http://brockallen.com/2012/06/28/cors-support-in-webapi-mvc-and-iis-with-thinktecture-identitymodel/

และสามารถปล่อย ACA-Origin แบบไดนามิกที่คุณต้องการได้


ดูเหมือนว่าห้องสมุดที่มีประโยชน์จริงๆ ขอบคุณสำหรับลิงค์
แซม

1

คุณสามารถเพิ่มโค้ดนี้ในโปรเจ็กต์ asp.net webapi ของคุณ

ในไฟล์Global.asax

    protected void Application_BeginRequest()
{
    string origin = Request.Headers.Get("Origin");
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
        Response.StatusCode = 200;
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
    }
}

1

ลองสิ่งนี้:

<add name="Access-Control-Allow-Origin" value="['URL1','URL2',...]" />


มีเอกสารหรือข้อมูลอ้างอิงสำหรับรูปแบบนี้หรือไม่?
Michael

0

คุณสามารถใช้มิดเดิลแวร์ของ Owin เพื่อกำหนดนโยบายคอร์ซึ่งคุณสามารถกำหนดคอร์ต้นทางได้หลายรายการ

return new CorsOptions
        {
            PolicyProvider = new CorsPolicyProvider
            {
                PolicyResolver = context =>
                {
                    var policy = new CorsPolicy()
                    {
                        AllowAnyOrigin = false,
                        AllowAnyMethod = true,
                        AllowAnyHeader = true,
                        SupportsCredentials = true
                    };
                    policy.Origins.Add("http://foo.com");
                    policy.Origins.Add("http://bar.com");
                    return Task.FromResult(policy);
                }
            }
        };

-3

คุณต้องการเพียง:

  • เพิ่ม Global.asax ในโครงการของคุณ
  • ลบ <add name="Access-Control-Allow-Origin" value="*" />จาก web.config ของคุณ
  • หลังจากนั้นเพิ่มสิ่งนี้ในApplication_BeginRequestวิธีการของ Global.asax:

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
    
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
        HttpContext.Current.Response.End();
    }
    

ฉันหวังว่าจะช่วยได้ ที่ทำงานให้ฉัน


การเพิ่ม "...- Origin: *" จะใช้งานได้ยกเว้นเมื่อคุณอนุญาตให้ใช้ข้อมูลรับรอง หากคุณตั้งค่า allow-credentials เป็น true คุณจะต้องระบุโดเมน (ไม่ใช่แค่ *) นั่นคือจุดสำคัญของปัญหานี้ มิฉะนั้นคุณสามารถระบุ "... allow-credentials: false" และดำเนินการได้
Richard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.