Access-control-allow-origin с несколькими доменами
В моем файле web.config я хотел бы указать несколько доменов для директивы access-control-allow-origin. Я не хочу использовать *. Я пробовал этот синтаксис:
<add name="Access-Control-Allow-Origin" value="http://localhost:1506, http://localhost:1502" />
этот
<add name="Access-Control-Allow-Origin" value="http://localhost:1506 http://localhost:1502" />
этот
<add name="Access-Control-Allow-Origin" value="http://localhost:1506; http://localhost:1502" />
и этот
<add name="Access-Control-Allow-Origin" value="http://localhost:1506" />
<add name="Access-Control-Allow-Origin" value="http://localhost:1502" />
но никто из них не работает. Какой правильный синтаксис?
12 ответов
Может быть только один Access-Control-Allow-Origin
заголовок ответа, и этот заголовок может иметь только одно значение источника. Поэтому, чтобы заставить это работать, вам нужно иметь некоторый код, который:
- Хватает
Origin
заголовок запроса. - Проверяет, является ли значение источника одним из значений в белом списке.
- Если оно действительно, устанавливает
Access-Control-Allow-Origin
заголовок с этим значением.
Я не думаю, что есть какой-либо способ сделать это исключительно через web.config.
if (ValidateRequest()) {
Response.Headers.Remove("Access-Control-Allow-Origin");
Response.AddHeader("Access-Control-Allow-Origin", Request.UrlReferrer.GetLeftPart(UriPartial.Authority));
Response.Headers.Remove("Access-Control-Allow-Credentials");
Response.AddHeader("Access-Control-Allow-Credentials", "true");
Response.Headers.Remove("Access-Control-Allow-Methods");
Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
}
Для IIS 7.5+ и Rewrite 2.0 вы можете использовать:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
<add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
</customHeaders>
</httpProtocol>
<rewrite>
<outboundRules>
<clear />
<rule name="AddCrossDomainHeader">
<match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?domain1\.com|(.+\.)?domain2\.com|(.+\.)?domain3\.com))" />
</conditions>
<action type="Rewrite" value="{C:0}" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
Объясняя переменную сервера RESPONSE_Access_Control_Allow_Origin
часть:
В Rewrite вы можете использовать любую строку после RESPONSE_
и он создаст заголовок ответа, используя оставшуюся часть слова в качестве имени заголовка (в данном случае Access-Control-Allow-Origin). Перезапись использует подчеркивания "_" вместо тире "-" (перезапись преобразует их в тире)
Объясняя переменную сервера HTTP_ORIGIN
:
Аналогично, в Rewrite вы можете получить любой заголовок запроса, используя HTTP_
в качестве префикса. Те же правила с тире (используйте подчеркивание "_" вместо тире "-").
В Web.API этот атрибут можно добавить с помощью Microsoft.AspNet.WebApi.Cors
как подробно описано на http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
В MVC вы можете создать атрибут фильтра, чтобы сделать эту работу за вас:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
AllowMultiple = true, Inherited = true)]
public class EnableCorsAttribute : FilterAttribute, IActionFilter {
private const string IncomingOriginHeader = "Origin";
private const string OutgoingOriginHeader = "Access-Control-Allow-Origin";
private const string OutgoingMethodsHeader = "Access-Control-Allow-Methods";
private const string OutgoingAgeHeader = "Access-Control-Max-Age";
public void OnActionExecuted(ActionExecutedContext filterContext) {
// Do nothing
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var isLocal = filterContext.HttpContext.Request.IsLocal;
var originHeader =
filterContext.HttpContext.Request.Headers.Get(IncomingOriginHeader);
var response = filterContext.HttpContext.Response;
if (!String.IsNullOrWhiteSpace(originHeader) &&
(isLocal || IsAllowedOrigin(originHeader))) {
response.AddHeader(OutgoingOriginHeader, originHeader);
response.AddHeader(OutgoingMethodsHeader, "GET,POST,OPTIONS");
response.AddHeader(OutgoingAgeHeader, "3600");
}
}
protected bool IsAllowedOrigin(string origin) {
// ** replace with your own logic to check the origin header
return true;
}
}
Затем либо включите его для определенных действий / контроллеров:
[EnableCors]
public class SecurityController : Controller {
// *snip*
[EnableCors]
public ActionResult SignIn(Guid key, string email, string password) {
Или добавьте его для всех контроллеров в Global.asax.cs
protected void Application_Start() {
// *Snip* any existing code
// Register global filter
GlobalFilters.Filters.Add(new EnableCorsAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);
// *snip* existing code
}
Для IIS 7.5+ вы можете использовать модуль IIS CORS: https://www.iis.net/downloads/microsoft/iis-cors-module
Ваш web.config должен выглядеть примерно так:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<cors enabled="true" failUnlistedOrigins="true">
<add origin="http://localhost:1506">
<allowMethods>
<add method="GET" />
<add method="HEAD" />
<add method="POST" />
<add method="PUT" />
<add method="DELETE" />
</allowMethods>
</add>
<add origin="http://localhost:1502">
<allowMethods>
<add method="GET" />
<add method="HEAD" />
<add method="POST" />
<add method="PUT" />
<add method="DELETE" />
</allowMethods>
</add>
</cors>
</system.webServer>
</configuration>
Вы можете найти ссылку на конфигурацию здесь: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference
Прочитав все ответы и попробовав их, никто из них не помог мне. При поиске в другом месте я обнаружил, что вы можете создать собственный атрибут, который затем сможете добавить в свой контроллер. Он перезаписывает блоки EnableCors и добавляет в него домены из белого списка.
Это решение работает хорошо, потому что оно позволяет вам иметь домены из белого списка в webconfig (appsettings) вместо того, чтобы размещать их в атрибуте EnableCors на вашем контроллере.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsByAppSettingAttribute : Attribute, ICorsPolicyProvider
{
const string defaultKey = "whiteListDomainCors";
private readonly string rawOrigins;
private CorsPolicy corsPolicy;
/// <summary>
/// By default uses "cors:AllowedOrigins" AppSetting key
/// </summary>
public EnableCorsByAppSettingAttribute()
: this(defaultKey) // Use default AppSetting key
{
}
/// <summary>
/// Enables Cross Origin
/// </summary>
/// <param name="appSettingKey">AppSetting key that defines valid origins</param>
public EnableCorsByAppSettingAttribute(string appSettingKey)
{
// Collect comma separated origins
this.rawOrigins = AppSettings.whiteListDomainCors;
this.BuildCorsPolicy();
}
/// <summary>
/// Build Cors policy
/// </summary>
private void BuildCorsPolicy()
{
bool allowAnyHeader = String.IsNullOrEmpty(this.Headers) || this.Headers == "*";
bool allowAnyMethod = String.IsNullOrEmpty(this.Methods) || this.Methods == "*";
this.corsPolicy = new CorsPolicy
{
AllowAnyHeader = allowAnyHeader,
AllowAnyMethod = allowAnyMethod,
};
// Add origins from app setting value
this.corsPolicy.Origins.AddCommaSeperatedValues(this.rawOrigins);
this.corsPolicy.Headers.AddCommaSeperatedValues(this.Headers);
this.corsPolicy.Methods.AddCommaSeperatedValues(this.Methods);
}
public string Headers { get; set; }
public string Methods { get; set; }
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
return Task.FromResult(this.corsPolicy);
}
}
internal static class CollectionExtensions
{
public static void AddCommaSeperatedValues(this ICollection<string> current, string raw)
{
if (current == null)
{
return;
}
var paths = new List<string>(AppSettings.whiteListDomainCors.Split(new char[] { ',' }));
foreach (var value in paths)
{
current.Add(value);
}
}
}
Я нашел это руководство онлайн, и оно работало как шарм:
Я думал, что бросил бы это здесь для любого нуждающегося.
Мне удалось решить это в коде обработки запросов, следуя совету от monsur.
string origin = WebOperationContext.Current.IncomingRequest.Headers.Get("Origin");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);
Посмотрите в библиотеку Thinktecture IdentityModel - она имеет полную поддержку CORS:
http://brockallen.com/2012/06/28/cors-support-in-webapi-mvc-and-iis-with-thinktecture-identitymodel/
И он может динамически излучать источник ACA, который вы хотите.
Попробуй это:
<add name="Access-Control-Allow-Origin" value="['URL1','URL2',...]" />
Вы можете использовать промежуточное ПО owin для определения политики Cors, в которой вы можете определить несколько источников Cors
return new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context =>
{
var policy = new CorsPolicy()
{
AllowAnyOrigin = false,
AllowAnyMethod = true,
AllowAnyHeader = true,
SupportsCredentials = true
};
policy.Origins.Add("http://foo.com");
policy.Origins.Add("http://bar.com");
return Task.FromResult(policy);
}
}
};
Мне повезло с надстройкой CORS IIS, которую вы можете загрузить с сайта Microsoft. Он поддерживает несколько доменов, допускает различные конфигурации аутентификации и позволяет предлагать только подмножество API-интерфейсов для разных доменов, если вы решите проявить фантазию.
Вам просто нужно добавить такой раздел в свой файл web.config.
<system.webServer>
<cors enabled="true" failUnlistedOrigins="true">
<add origin="http://server1.com"
allowCredentials="true"
allowed="true"
maxAge="120">
</add>
<add origin="http://server2.com"
allowed="true"
allowCredentials="true"
maxAge="120">
</add>
</cors>
</system.webServer>
Если вы хотите погрузиться в варианты, посмотрите здесь.
Следует отметить одну вещь, которая сначала сбила меня с толку: это конфликтует с другими настройками web.config, такими как ручное добавление
Access-Control-Origin
заголовок самостоятельно, поэтому делайте только одно или другое; не оба.
Еще одна вещь, которую следует отметить, это то, что даже если у вас идеально настроен сервер, вам могут потребоваться настройки на стороне клиента, чтобы фактически его использовать. Например, вот параметры метода выборки Javascript, которые необходимо использовать для вызова методов для сервера CORS с проверкой подлинности.
fetch(url, {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'include', // include, *same-origin, omit
})
Удачи.
Вы можете добавить этот код в свой проект asp.net webapi
в файле Global.asax
protected void Application_BeginRequest()
{
string origin = Request.Headers.Get("Origin");
if (Request.HttpMethod == "OPTIONS")
{
Response.AddHeader("Access-Control-Allow-Origin", origin);
Response.AddHeader("Access-Control-Allow-Headers", "*");
Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
Response.StatusCode = 200;
Response.End();
}
else
{
Response.AddHeader("Access-Control-Allow-Origin", origin);
Response.AddHeader("Access-Control-Allow-Headers", "*");
Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
}
}
Вам нужно только:
- добавить Global.asax в ваш проект,
удалить из вашего web.config.
- после добавления в метод Application_BeginRequest файла Global.asax это:
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
HttpContext.Current.Response.End();
}
Я надеюсь, что это поможет. это работа для меня.