使用PUT和DELETE有多个起源请求时如何解决的ASP.NET Web API CORS预检问题?

问题描述:

我有一个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身份验证,它不兼容。除此之外,我只想让这三个网址。 –

我能够进一步定制在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; 
    } 
]); 

就是这样。这解决了我的问题。如果其他人仍然有问题,我建议你阅读下列出版物,这让我达到我的回答是:

创建使用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