2016-09-21 51 views
6

我有一個ASP.NET的Web API,它是由三個不同的SPA叫。我正在爲Web API使用Windows身份驗證。我最初試圖在Web.config這樣的配置CORS:使用PUT和DELETE有多個起源請求時如何解決的ASP.NET Web API CORS預檢問題?

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

這導致此問題的預檢:

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. 

,我在Global.asax.cs中添加以下方法解決:

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

這種做法非常完美的一個SPA。我想我可以去Web.config並添加像這樣的其他起源:

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

但顯然這是不允許的。這將產生以下錯誤:

​​

所以爲了嘗試解決這個問題,我改變了我的做法,而是決定嘗試在WebAPIConfig.cs配置CORS,在註冊的方法是這樣的:

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

我認爲這會工作,但現在我使用的時候PUT和DELETE請求,我不知道如何解決這個問題再有預檢錯誤。我調試了Application_BeginRequest方法,它仍在沖洗OPTIONS請求,所以我不知道是什麼導致了這個錯誤。有誰知道我可以如何解決這個問題?

編輯:

預檢錯誤的打印:

enter image description here

+0

@Aravind對不起,我無法真正理解你提出的解決方案因爲SO由於某種原因使報價翻倍。你能否以另一種方式寫下來? –

+0

您可以使用'new EnableCorsAttribute(「*」,「*」,「*」)來允許所有域和方法;'更好的方式來處理這個問題,就是使用ICorsPolicyProvider創建自己的自定義屬性並實現GetCorsPolicyAsync方法。 – Paresh

+0

@Paresh但我不能使用*,因爲我使用的是Windows身份驗證,它不兼容。除此之外,我只想讓這三個網址。 –

回答

7

我能夠進一步定製在Global.asax.cs中的方法的Application_BeginRequest,這樣解決我的問題:

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

這段代碼確實是缺少頭添加到OPTIONS響應(預檢請求)導致預檢錯誤。因爲我有不同的起源叫我的網絡API,我使用Request.Headers.GetValues("Origin")[0])設置在響應起源dinamically。

在WebApiConfig.cs我還指定了不同的起源,但用在標題和方法通配符,以及設置SupportsCredentials爲true,像這樣:

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

另外,如果你正在使用像我這樣的AngularJS,你必須配置$ http來使用憑據。這可以像這樣在全局上配置:

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

就是這樣。這解決了我的問題。如果其他人仍然有問題,我建議你閱讀下列出版物,這讓我達到我的回答是:

1

創建使用ICorsPolicyProvider類似以下檢查自定義屬性如果請求的原點允許或不允許

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

要使用它,將它添加到您的API控制器

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

這個解決方案不會讓我必須將該註釋添加到所有控制器嗎?我寧願有一個解決方案,我可以在全球配置一切。 –

+0

我認爲你可以在全局層面上使用'config.Filters.Add(new EnableCorsForAPIKeysAttribute());'' – Paresh