使用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请求,所以我不知道是什么导致了这个错误。有谁知道我可以如何解决这个问题?
编辑:
预检错误的打印:
我能够进一步定制在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;
}
]);
就是这样。这解决了我的问题。如果其他人仍然有问题,我建议你阅读下列出版物,这让我达到我的回答是:
- http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
- https://evolpin.wordpress.com/2012/10/12/the-cors/
- AngularJS $http, CORS and http authentication
- AngularJS performs an OPTIONS HTTP request for a cross-origin resource
- AngularJS POST Fails: Response for preflight has invalid HTTP status code 404
创建使用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
{
}
这个解决方案不会让我必须将该注释添加到所有控制器吗?我宁愿有一个解决方案,我可以在全球配置一切。 –
我认为你可以在全局层面上使用'config.Filters.Add(new EnableCorsForAPIKeysAttribute());'' – Paresh
@Aravind对不起,我无法真正理解你提出的解决方案因为SO由于某种原因使报价翻倍。你能否以另一种方式写下来? –
您可以使用'new EnableCorsAttribute(“*”,“*”,“*”)来允许所有域和方法;'更好的方式来处理这个问题,就是使用ICorsPolicyProvider创建自己的自定义属性并实现GetCorsPolicyAsync方法。 – Paresh
@Paresh但我不能使用*,因为我使用的是Windows身份验证,它不兼容。除此之外,我只想让这三个网址。 –