Access-control-allow-origin với nhiều miền


97

Trong web.config của tôi, tôi muốn chỉ định nhiều miền cho access-control-allow-originchỉ thị. Tôi không muốn sử dụng *. Tôi đã thử cú pháp này:

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

cái này

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

cái này

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

và cái này nữa

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

nhưng không ai trong số họ hoạt động. Cú pháp chính xác là gì?

Câu trả lời:


77

Chỉ có thể có một Access-Control-Allow-Origintiêu đề phản hồi và tiêu đề đó chỉ có thể có một giá trị gốc. Do đó, để làm việc này, bạn cần phải có một số mã sau:

  1. Lấy Origintiêu đề yêu cầu.
  2. Kiểm tra xem giá trị gốc có phải là một trong các giá trị nằm trong danh sách trắng hay không.
  3. Nếu nó hợp lệ, hãy đặt Access-Control-Allow-Origintiêu đề với giá trị đó.

Tôi không nghĩ rằng có bất kỳ cách nào để làm điều này chỉ thông qua 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
Điều đó trả lời câu hỏi của tôi. Tôi không chắc chắn lý do tại sao Microsoft không cho phép xác định nhiều nguồn gốc trong web.config mặc dù ....
Sam

17
Tôi có thể thêm mã này ở đâu? Tôi có các tệp văn bản thuần túy được tạo bởi máy chủ và đọc qua AJAX, không có mã nào cả. Tôi có thể đặt mã ở đâu để hạn chế quyền truy cập vào các tệp văn bản trong thư mục của mình?
Harry

3
@Simon_Weaver có một *giá trị cho phép bất kỳ nguồn gốc nào truy cập tài nguyên. Tuy nhiên, câu hỏi ban đầu là hỏi về việc đưa vào danh sách trắng một tập hợp các miền.
thưa ông

2
vì tôi mới sử dụng asp .net, tôi có thể hỏi tôi có thể đặt mã này ở đâu trong dự án api web asp .net của mình không?
Amrit,

91

Đối với IIS 7.5+ và Rewrite 2.0, bạn có thể sử dụng:

<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>

Giải thích RESPONSE_Access_Control_Allow_Originphần biến máy chủ :
Trong Viết lại, bạn có thể sử dụng bất kỳ chuỗi nào sau RESPONSE_đó và nó sẽ tạo Tiêu đề phản hồi bằng cách sử dụng phần còn lại của từ làm tên tiêu đề (trong trường hợp này là Access-Control-Allow-Origin). Viết lại sử dụng dấu gạch dưới "_" thay vì dấu gạch ngang "-" (viết lại chuyển đổi chúng thành dấu gạch ngang)

Giải thích biến máy chủ HTTP_ORIGIN:
Tương tự, trong Viết lại, bạn có thể lấy bất kỳ Tiêu đề Yêu cầu nào bằng cách sử dụng HTTP_làm tiền tố. Quy tắc tương tự với dấu gạch ngang (sử dụng dấu gạch dưới "_" thay vì dấu gạch ngang "-").


Bạn có thể nghĩ ra bất kỳ lý do nào khiến điều này không hoạt động với IIS 7.5 không?
Phil Ricketts

Tôi nghĩ rằng nó sẽ làm việc. Tôi đã chỉ định phiên bản IIS 8.5 vì đó là nơi tôi đã thử nghiệm nó.
Paco Zarate

4
@PacoZarate Tuyệt vời, mẹo hay. Để đơn giản hóa regex và làm cho nó chung chung hơn, bạn có thể sử dụng - (http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net))). Bằng cách đó, bạn có thể thêm các miền khác khá dễ dàng và hỗ trợ nhiều miền Cấp cao nhất (ví dụ: com, org, net, v.v.).
Merlin

4
Chỉ cần thử điều này trong IIS 7.5. Có vẻ như đang hoạt động tốt.
lời tiên tri

2
Bạn gặp sự cố với bộ nhớ đệm? Sau khi tinh chỉnh web.config, trang web đầu tiên tôi truy cập vẫn phù hợp, nhưng trang thứ hai trả về tiêu đề giống như trang đầu tiên. Do đó khiến các miền không quá khớp nhau.
Airn5475

20

Trong Web.API thuộc tính này có thể được thêm vào bằng cách sử dụng Microsoft.AspNet.WebApi.Corschi tiết tại http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Trong MVC, bạn có thể tạo một thuộc tính bộ lọc để thực hiện công việc này cho bạn:

[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;
    }
}

Sau đó, bật nó cho các hành động / bộ điều khiển cụ thể:

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

Hoặc thêm nó cho tất cả các bộ điều khiển trong 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
}

Bạn có biết phiên bản .Net / MVC này hoạt động cho những gì không?
Keab42,

Tôi đang sử dụng điều này thành công trong .net 4 / MVC 3 - theo như tôi biết thì nó sẽ hoạt động trong các phiên bản cao hơn nhưng có thể có một cách ưu tiên để đăng ký bộ lọc chung trong các phiên bản MVC sau.
Nhà thờ Rob

chỉ xin lưu ý rằng chỉ giải pháp WEB API 2 của nó. không dành cho WEB API 1.
Samih A

5

Sau khi đọc tất cả các câu trả lời và thử chúng, không ai trong số họ giúp tôi. Những gì tôi tìm thấy trong khi tìm kiếm ở những nơi khác là bạn có thể tạo một thuộc tính tùy chỉnh mà sau đó bạn có thể thêm vào bộ điều khiển của mình. Nó ghi đè các EnableCors và thêm các miền có trong danh sách trắng vào đó.

Giải pháp này đang hoạt động tốt vì nó cho phép bạn có các miền thuộc danh sách trắng trong webconfig (ứng dụng cài đặt) thay vì mã hóa chúng trong thuộc tính EnableCors trên bộ điều khiển của bạn.

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

Tôi tìm thấy hướng dẫn này trực tuyến và nó hoạt động như một sự quyến rũ:

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

Tôi nghĩ rằng tôi sẽ để nó ở đây cho bất kỳ ai cần.


Đây là một câu trả lời chỉ có liên kết. Thay vào đó, hãy đặt câu trả lời cho riêng nó.
Phục hồi Monica

1
Ok, tôi là người mới ở đây, điều này giống như những gì nó sẽ được cung cấp?
Helpha

3

Tôi đã giải quyết được vấn đề này trong Mã xử lý yêu cầu theo lời khuyên từ 'ông'.

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

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

Đó là cách để làm trong biểu mẫu web chẳng hạn. Chỉ cần sử dụng Request.Headers khi có sẵn. Và, nếu cần, hãy sử dụng danh sách trắng để chỉ lọc các miền được phép.
Rút khỏi

3
Đây là tốt như thêm <add name = "Access-Control-Allow-Origin" value = "*" /> trong file web.config
Isaiah4110

3

Đối với IIS 7.5+, bạn có thể sử dụng Mô-đun IIS CORS: https://www.iis.net/downloads/microsoft/iis-cors-module

Web.config của bạn sẽ giống như sau:

<?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>

Bạn có thể tìm tham khảo cấu hình tại đây: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference


Nếu điều này hoạt động như nó nói, tôi ước bạn đã đăng điều này 3 năm trước! Ái chà!
Michael


1

Bạn có thể thêm mã này vào dự án webapi asp.net của mình

trong tệp 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");
    }
}

0

Bạn có thể sử dụng phần mềm trung gian owin để xác định chính sách cors trong đó bạn có thể xác định nhiều nguồn gốc cors

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

Bạn chỉ cần:

  • thêm Global.asax vào dự án của bạn,
  • xóa <add name="Access-Control-Allow-Origin" value="*" />khỏi web.config của bạn.
  • sau đó, thêm điều này vào Application_BeginRequestphương thức của 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();
    }

Tôi hy vọng điều này giúp đỡ. điều đó làm việc cho tôi.


Thêm "...- Nguồn gốc: *" hoạt động trừ khi bạn cho phép thông tin đăng nhập. Nếu bạn đã đặt thông tin cho phép thành true, thì bạn phải chỉ định một miền (không chỉ đơn giản là *). Đó là mấu chốt của vấn đề này. Nếu không, bạn chỉ có thể chỉ định "... allow-credentials: false" và thực hiện với nó.
Richard
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.