2016-09-21 16 views
6

Tôi có một API web ASP.NET đang được gọi bằng ba SPA khác nhau. Tôi đang sử dụng xác thực cửa sổ cho API web. Ban đầu tôi đã cố gắng để cấu hình CORS trong Web.config như thế này:Làm thế nào để giải quyết vấn đề ASP.NET Web API CORS Preflight khi sử dụng các yêu cầu PUT và DELETE với nhiều nguồn gốc?

<httpProtocol> 
    <customHeaders> 
     <add name="Access-Control-Allow-Origin" value="http://localhost:63342" /> 
     <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" /> 
     <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" /> 
     <add name="Access-Control-Allow-Credentials" value="true" /> 
    </customHeaders> 
</httpProtocol> 

này gây ra vấn đề này preflight:

Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin (...) is therefore not allowed access. 

mà tôi giải quyết bằng cách thêm các phương pháp sau đây trong Global.asax.cs:

protected void Application_BeginRequest() 
{ 
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") 
    { 
     Response.Flush(); 
    } 
} 

Phương pháp này hoạt động hoàn hảo cho một SPA duy nhất. Tôi nghĩ rằng tôi có thể vào Web.config và thêm các nguồn gốc khác như sau:

<add name="Access-Control-Allow-Origin" value="http://localhost:63342,http://localhost:63347,http://localhost:63345/> 

nhưng rõ ràng là không được phép. Đây sản xuất các lỗi sau:

The 'Access-Control-Allow-Origin' header contains multiple values (...), but only one is allowed. Origin (...) is therefore not allowed access. 

Vì vậy, để thử và sửa lỗi này, tôi đã thay đổi cách tiếp cận của tôi và thay vào đó quyết định thử để cấu hình CORS trên WebAPIConfig.cs, trong phương pháp ký như thế này:

var cors = new EnableCorsAttribute("http://localhost:63342,http://localhost:63347,http://localhost:63345", "Origin, X-Requested-With, Content-Type, Accept", "GET, POST, PUT, DELETE"); 
cors.SupportsCredentials = true; 
config.EnableCors(cors); 

Tôi nghĩ rằng điều này sẽ làm việc nhưng bây giờ tôi có lỗi preflight một lần nữa khi sử dụng yêu cầu PUT và DELETE và tôi không biết làm thế nào để sửa lỗi này. Tôi đã gỡ rối phương thức Application_BeginRequest và nó vẫn đang xóa yêu cầu OPTIONS vì vậy tôi không có ý tưởng về nguyên nhân gây ra lỗi này. Có ai biết làm thế nào tôi có thể giải quyết vấn đề này?

EDIT:

Các in của lỗi preflight:

enter image description here

+0

@Aravind Tôi xin lỗi tôi không thể thực sự hiểu được giải pháp bạn đề nghị ested vì SO tăng gấp đôi dấu ngoặc kép vì một lý do nào đó. Bạn có thể viết nó theo cách khác không? –

+0

Bạn có thể cho phép tất cả các miền và phương thức bằng cách sử dụng 'EnableCorsAttribute mới (" * "," * "," * ");' Cách tốt hơn để xử lý việc này là tạo thuộc tính tùy chỉnh của riêng bạn bằng cách sử dụng ICorsPolicyProvider và triển khai phương thức GetCorsPolicyAsync. – Paresh

+0

@Paresh Nhưng tôi không thể sử dụng * vì tôi đang sử dụng xác thực cửa sổ và nó không tương thích. Bên cạnh đó tôi chỉ muốn cho phép ba url đó. –

Trả lời

7

tôi đã có thể giải quyết vấn đề của tôi bằng cách thêm tùy phương pháp Application_BeginRequest trong Global.asax.cs, như thế này:

protected void Application_BeginRequest() 
{ 
    if (Request.HttpMethod == "OPTIONS") 
    { 
     Response.StatusCode = (int)HttpStatusCode.OK; 
     Response.AppendHeader("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin")[0]); 
     Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept"); 
     Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); 
     Response.AppendHeader("Access-Control-Allow-Credentials", "true"); 
     Response.End(); 
    } 
} 

gì mã này làm là thêm các tiêu đề thiếu để đáp ứng OPTIONS (yêu cầu preflight) đã gây ra lỗi preflight. Vì tôi có nguồn gốc khác nhau gọi API web của tôi, tôi đang sử dụng Request.Headers.GetValues("Origin")[0]) để đặt nguồn gốc trong phản hồi theo chế độ ăn tối.

Trong WebApiConfig.cs tôi vẫn xác định nguồn gốc khác nhau nhưng sử dụng ký tự đại diện trên các tiêu đề và phương pháp, cũng như thiết lập các SupportsCredentials true, như thế này:

var cors = new EnableCorsAttribute("http://localhost:63342,http://localhost:63347,http://localhost:63345", "*", "*"); 
cors.SupportsCredentials = true; 
config.EnableCors(cors); 

Ngoài ra, nếu bạn đang sử dụng AngularJS như tôi, bạn phải cấu hình $ http để sử dụng thông tin đăng nhập.Điều này có thể được định cấu hình trên toàn cầu như thế này:

angular 
.module('Application') 
.config(['$httpProvider', 
    function config($httpProvider) { 
     $httpProvider.defaults.withCredentials = true; 
    } 
]); 

Và đó là nó. Điều này giải quyết được vấn đề của tôi. Nếu ai đó vẫn gặp sự cố, tôi khuyên bạn nên đọc các ấn phẩm sau đây, mà đã giúp tôi đạt được câu trả lời của tôi:

1

Tạo thuộc tính tùy chỉnh sử dụng ICorsPolicyProvider cái gì đó như sau để kiểm tra xem nguồn gốc yêu cầu được phép hay không

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = false)] 
    public class EnableCorsForAPIKeysAttribute : 
     Attribute, ICorsPolicyProvider, IFilter 
    { 
     public async Task<CorsPolicy> GetCorsPolicyAsync(
      HttpRequestMessage request, CancellationToken cancellationToken) 
     { 
      var corsRequestContext = request.GetCorsRequestContext(); 
      var originRequested = corsRequestContext.Origin; 
      if (await IsValidOrigin(originRequested)) //Check if requested origin is valid or not 
      { 
       // Grant CORS request 
       var policy = new CorsPolicy 
       { 
        AllowAnyHeader = true, 
        AllowAnyMethod = true 
       }; 
       policy.Origins.Add(originRequested); 
       return policy; 
      } 
      else 
      { 
       // Reject CORS request 
       return null; 
      } 
     } 

     public bool AllowMultiple { get {return false;} } 
    } 

Để sử dụng nó, hãy thêm nó vào bộ điều khiển API của bạn

[EnableCorsForAPIKeys] 
public class APIBaseController : ApiController 
{ 
} 
+0

Giải pháp này có giúp tôi phải thêm chú thích đó vào tất cả các bộ điều khiển không? Tôi thà có một giải pháp mà tôi có thể cấu hình mọi thứ trên toàn cầu. –

+0

Tôi nghĩ rằng bạn có thể làm điều đó ở cấp độ toàn cầu bằng cách sử dụng 'config.Filters.Add (mới EnableCorsForAPIKeysAttribute());' – Paresh

Các vấn đề liên quan