Как решить проблему ASP.NET проблема с веб-API CORS Preflight при использовании запросов PUT и DELETE с несколькими источниками?
У меня есть ASP.NET веб-API, который вызывается тремя различными SPA. Я использую проверку подлинности windows для веб-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.асакс.cs:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
Этот подход идеально работал для одного СПА. Я думал, что смогу выйти в Сеть.config и добавить другие источники, как это:
<add name="Access-Control-Allow-Origin" value="http://localhost:63342,http://localhost:63347,http://localhost:63345/>
Но, по-видимому, это не допускается. Это привело к следующей ошибке:
The 'Access-Control-Allow-Origin' header contains multiple values (...), but only one is allowed. Origin (...) is therefore not allowed access.
Поэтому, чтобы попытаться исправить это, я изменил свой подход и вместо этого решил попробовать настроить CORS на WebAPIConfig.cs, в регистре метод выглядит следующим образом:
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, и он все еще топится параметры запроса, так что я понятия не имею, что вызывает эту ошибку. Кто-нибудь знает, как я могу решить эту проблему?
Правка:
Печать предполетной ошибки:
2 ответа:
Я смог решить свою проблему, дополнительно настроив метод Application_BeginRequest в Global.асакс.cs, например:
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])
для динамического задания источника в ответе.В 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 и HTTP аутентификация
- AngularJS выполняет HTTP-запрос опций для ресурса кросс-происхождения
- AngularJS POST Fails: ответ на предполетный запрос имеет недопустимый код состояния HTTP 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 { }