Настройка Access-Control-Allow-Origin в ASP.Net MVC - самый простой способ
У меня есть простой метод action, который возвращает JSON. Он работает на ajax.example.com. Мне нужно получить доступ к этому с другого сайта someothersite.com.
Если я попытаюсь позвонить, я получу ожидаемое...:
Origin http://someothersite.com is not allowed by Access-Control-Allow-Origin.
Я знаю два способа обойти это: JSONP и создание собственного HttpHandler для установки заголовка.
Нет ли более простого способа?
Разве невозможно для простого действия определить список разрешенных источников или просто разрешить всем? Может быть, фильтр действий?
Оптимальным было бы...
return json(mydata, JsonBehaviour.IDontCareWhoAccessesMe);
15 ответов
Для простых контроллеров ASP.NET MVC
Создать новый атрибут
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
base.OnActionExecuting(filterContext);
}
}
Отметьте свое действие:
[AllowCrossSiteJson]
public ActionResult YourMethod()
{
return Json("Works better?");
}
Для ASP.NET Web API
using System;
using System.Web.Http.Filters;
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Response != null)
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
base.OnActionExecuted(actionExecutedContext);
}
}
Пометить весь контроллер API:
[AllowCrossSiteJson]
public class ValuesController : ApiController
{
Или отдельные вызовы API:
[AllowCrossSiteJson]
public IEnumerable<PartViewModel> Get()
{
...
}
Для Internet Explorer <= v9
IE <= 9 не поддерживает CORS. Я написал javascript, который будет автоматически направлять эти запросы через прокси. Это все на 100% прозрачно (вам просто нужно включить мой прокси и скрипт).
Загрузите его с помощью nuget corsproxy
и следуйте прилагаемым инструкциям.
Если вы используете IIS 7+, вы можете поместить файл web.config в корень папки с этим в разделе system.webServer:
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
См.: http://msdn.microsoft.com/en-us/library/ms178685.aspx И: http://enable-cors.org/
Я столкнулся с проблемой, когда браузер отказывался обслуживать контент, который он извлек, когда запрос передавался в файлах cookie (например, xhr имел withCredentials=true
), а сайт имел Access-Control-Allow-Origin
установлен в *
, (Ошибка в Chrome была: "Не удается использовать подстановочный знак в Access-Control-Allow-Origin, когда флаг учетных данных имеет значение true".)
Основываясь на ответе @jgauffin, я создал его, который в основном представляет собой способ обойти эту конкретную проверку безопасности браузера, поэтому будьте осторожны с emptor.
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// We'd normally just use "*" for the allow-origin header,
// but Chrome (and perhaps others) won't allow you to use authentication if
// the header is set to "*".
// TODO: Check elsewhere to see if the origin is actually on the list of trusted domains.
var ctx = filterContext.RequestContext.HttpContext;
var origin = ctx.Request.Headers["Origin"];
var allowOrigin = !string.IsNullOrWhiteSpace(origin) ? origin : "*";
ctx.Response.AddHeader("Access-Control-Allow-Origin", allowOrigin);
ctx.Response.AddHeader("Access-Control-Allow-Headers", "*");
ctx.Response.AddHeader("Access-Control-Allow-Credentials", "true");
base.OnActionExecuting(filterContext);
}
}
Это действительно просто, просто добавьте это в web.config
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost" />
<add name="Access-Control-Allow-Headers" value="X-AspNet-Version,X-Powered-By,Date,Server,Accept,Accept-Encoding,Accept-Language,Cache-Control,Connection,Content-Length,Content-Type,Host,Origin,Pragma,Referer,User-Agent" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />
<add name="Access-Control-Max-Age" value="1000" />
</customHeaders>
</httpProtocol>
</system.webServer>
В Origin поместите все домены, которые имеют доступ к вашему веб-серверу, в заголовки поместите все возможные заголовки, которые может использовать любой HTTP-запрос ajax, в методы поместите все методы, которые вы разрешаете на своем сервере.
С уважением:)
Иногда глагол OPTIONS также вызывает проблемы
Просто: обновите ваш web.config следующим
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
</system.webServer>
И обновите заголовки веб-службы / контроллера с помощью httpGet и httpOptions
// GET api/Master/Sync/?version=12121
[HttpGet][HttpOptions]
public dynamic Sync(string version)
{
В WebAPI 2 теперь есть пакет для CORS, который можно установить с помощью:Install-Package Microsoft.AspNet.WebApi.Cors -pre -project WebServic
После того, как это установлено, следуйте за этим для кода: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
После целого вечера борьбы я наконец заставил это работать. После некоторой отладки я обнаружил, что проблема, с которой я столкнулся, заключалась в том, что мой клиент отправлял так называемый запрос параметров предварительной проверки, чтобы проверить, разрешено ли приложению отправлять почтовый запрос с предоставленным источником, методами и заголовками. Мне не хотелось использовать Owin или APIController, поэтому я начал копать и придумал следующее решение с использованием только ActionFilterAttribute. Особенно важна часть "Access-Control-Allow-Headers", поскольку упомянутые там заголовки должны совпадать с заголовками, которые отправляет ваш запрос.
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MyNamespace
{
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequest request = HttpContext.Current.Request;
HttpResponse response = HttpContext.Current.Response;
// check for preflight request
if (request.Headers.AllKeys.Contains("Origin") && request.HttpMethod == "OPTIONS")
{
response.AppendHeader("Access-Control-Allow-Origin", "*");
response.AppendHeader("Access-Control-Allow-Credentials", "true");
response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
response.End();
}
else
{
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
response.AppendHeader("Access-Control-Allow-Origin", "*");
response.AppendHeader("Access-Control-Allow-Credentials", "true");
if (request.HttpMethod == "POST")
{
response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE");
response.AppendHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-RequestDigest, Cache-Control, Content-Type, Accept, Access-Control-Allow-Origin, Session, odata-version");
}
base.OnActionExecuting(filterContext);
}
}
}
}
Наконец, мой метод действия MVC выглядит так. Здесь важно также упомянуть параметры HttpVerbs, потому что в противном случае предварительный запрос не будет выполнен.
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Options)]
[AllowCrossSiteJson]
public async Task<ActionResult> Create(MyModel model)
{
return Json(await DoSomething(model));
}
Добавьте эту строку в ваш метод, если вы используете API.
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
Этот урок очень полезен. Чтобы дать краткое резюме:
Используйте пакет CORS, доступный на Nuget:
Install-Package Microsoft.AspNet.WebApi.Cors
В вашем
WebApiConfig.cs
файл, добавитьconfig.EnableCors()
кRegister()
метод.Добавьте атрибут к контроллерам, которые вам нужны для обработки cors:
[EnableCors(origins: "<origin address in here>", headers: "*", methods: "*")]
public ActionResult ActionName(string ReqParam1, string ReqParam2, string ReqParam3, string ReqParam4)
{
this.ControllerContext.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin","*");
/*
--Your code goes here --
*/
return Json(new { ReturnData= "Data to be returned", Success=true }, JsonRequestBehavior.AllowGet);
}
Мы можем передать заголовки Access-Control-Expose-Headers разными способами.
- Как объяснил jgauffin, мы можем создать новый атрибут.
- Как пояснил LaundroMatt, мы можем добавить файл web.config.
Другой способ - мы можем добавить код, как показано ниже в файле webApiconfig.cs.
config.EnableCors (новый EnableCorsAttribute ("", headers: "", методы: "*",posedHeaders: "TestHeaderToExpose") { SupportsCredentials = true });
Или мы можем добавить приведенный ниже код в файл Global.Asax.
protected void Application_BeginRequest()
{
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
//These headers are handling the "pre-flight" OPTIONS call sent by the browser
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials", "true");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:4200");
HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "TestHeaderToExpose");
HttpContext.Current.Response.End();
}
}
Я написал это для вариантов. Пожалуйста, измените так же, как вам нужно.
Удачного кодирования!
Я использую DotNet Core MVC, и после нескольких часов борьбы с пакетами nuget, Startup.cs, атрибутами и этим местом я просто добавил это в действие MVC:
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Я понимаю, что это довольно неуклюже, но это все, что мне нужно, и больше никто не хотел добавлять эти заголовки. Надеюсь, это поможет кому-то другому!
В Web.config введите следующее
<system.webServer>
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Origin" value="http://localhost:123456(etc)" />
</customHeaders>
</httpProtocol>
Если вы используете IIS, я бы предложил попробовать модуль IIS CORS.
Это легко настроить и работает для всех типов контроллеров.
Вот пример конфигурации:
<system.webServer>
<cors enabled="true" failUnlistedOrigins="true">
<add origin="*" />
<add origin="https://*.microsoft.com"
allowCredentials="true"
maxAge="120">
<allowHeaders allowAllRequestedHeaders="true">
<add header="header1" />
<add header="header2" />
</allowHeaders>
<allowMethods>
<add method="DELETE" />
</allowMethods>
<exposeHeaders>
<add header="header1" />
<add header="header2" />
</exposeHeaders>
</add>
<add origin="http://*" allowed="false" />
</cors>
</system.webServer>
Чтобы основной ответ работал в MVC 5.
Используйте System.Web.Mvc вместо System.Web.Http.Filters.
using System;
using System.Web.Mvc;
// using System.Web.Http.Filters;
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
...
}