Налаштування Access-Control-Allow-Origin в ASP.Net MVC - найпростіший можливий метод


206

У мене є простий метод дій, який повертає деякий 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);

1
Подивіться тут на vNext та MVC6: neelbhatt40.wordpress.com/2015/09/10/…
Neel

Відповіді:


381

Для звичайних контролерів 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?");
}

Для веб-API ASP.NET

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і дотримуйтесь інструкцій, що додаються .

Повідомлення в блозі | Вихідний код


8
Дивовижний! Я люблю MVC + U!
Пьотр Кула

2
в захваті від елегантності цього рішення
BraveNewMath

3
Ви можете легко розширити атрибут, щоб прийняти певне походження, якщо хочете обмежити CORS у власних доменах.
Петрус Терон

2
Ви повинні мати змогу додати це до RegisterHttpFilters у вашому App_Start \ FilterConfig правильно? Це може застосувати його до всіх контролерів Api у вашому проекті. З'єднавши це з коментарем паштету вище, ви можете обмежити CORS вашим доменом для всіх контролерів.
bdwakefield

9
Нещодавно я оновив наш проект до MVC 5 і спробував це зробити. Навіть додавання заголовка у фільтр, здається, не працює. Коли я переглядаю запит у мережі, заголовок у відповіді відсутній. Чи є ще щось, що потрібно зробити, щоб це працювало?
Kneemin

121

Якщо ви використовуєте 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/#how-iis7


1
Я не можу більше пригадати, чому цей метод не завжди працює в IIS 7+
LaundroMatt

Хм. Єдиною причиною, на яку я можу вважати, що це не спрацює, це те, що запит походить від браузера, який не є CORS Але я продовжуватиму розслідування.
sellmeadog

29
Також це зробить весь веб-сайт CORS-приємним. Якщо хтось хоче позначити лише одну дію чи контролер як дружній для CORS, то прийнята відповідь набагато краща.
Лев Дубінець

1
Якщо ви бачите розділ ASP.Net , він має підказку : "Примітка. Цей підхід сумісний з IIS6, IIS7 Classic Mode та IIS7 Integrated Mode."
percebus

1
Коли я публікую свою програму в середовищі SharePoint, я стикаюся з проблемою міждоменного домену. Коли я запускаю свій додаток у локальному середовищі, мій додаток працює нормально, але коли я публікую його лайно на мій сайт sharepoint, він перенаправляє на сторінку помилок на виклику форми Ajax.Begin. Я спробував це рішення, але це не працює для мене. Чи є інша альтернатива цьому?
Jyotsna Wadhwani

22

Я зіткнувся з проблемою, коли браузер відмовився подавати вміст, який він отримав, коли запит передається у файлах cookie (наприклад, у xhr був його withCredentials=true), і сайт Access-Control-Allow-Originналаштував *. (Помилка в Chrome полягала в тому, що "Неможливо використовувати підстановку в Access-Control-Allow-Origin, коли прапор облікових даних є істинним.")

Спираючись на відповідь від @jgauffin, я створив це, що в основному є способом обходу певної перевірки безпеки веб-переглядача, тому застереження виправника.

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);
    }
}

Це було особливо корисно, дякую.
cklimowski

15

Це дійсно просто, просто додайте це в 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 помістіть усі домени, які мають доступ до вашого веб-сервера, в заголовки покладіть всі можливі заголовки, якими може користуватися будь-який запит ajax http, в методи розміщуйте всі методи, які ви дозволяєте на своєму сервері

З повагою :)


Додавання "Авторизації" в Access-Control-Allow-Headers також може бути корисним, якщо ви плануєте використовувати авторизовані запити.
AFAct

9

Іноді дієслово 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) 
        {

До речі, в sitefinity вам потрібно додати * до розширених налаштувань системи в розділі безпеки
Bishoy Hanna

які файли, в яких мені потрібно оновити заголовки контролера?
користувач3281466


5

Додайте цей рядок до свого методу, якщо ви використовуєте API.

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*"); 

4

Цей підручник дуже корисний. Щоб дати короткий підсумок:

  1. Використовуйте пакет CORS, доступний на Nuget: Install-Package Microsoft.AspNet.WebApi.Cors

  2. У своєму WebApiConfig.csфайлі додайте config.EnableCors()до Register()методу.

  3. Додайте атрибут до контролерів, з якими потрібно обробляти корзи:

[EnableCors(origins: "<origin address in here>", headers: "*", methods: "*")]


Мені довелося скористатися цим методом, тому що мені потрібно було встановити користувальницький заголовок у своєму запиті, а метод спеціального атрибута не працював із запитом перед польотом браузерів. Здається, це працює у всіх випадках.
lehn0058

3
    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);
    }

2

Існують різні способи передачі заголовків Access-Control-Expose-заголовків.

  • Як пояснив jgauffin, ми можемо створити новий атрибут.
  • Як пояснив LaundroMatt, ми можемо додати у файл web.config.
  • Ще один спосіб - ми можемо додати код, як показано нижче, у файл webApiconfig.cs.

    config.EnableCors (новий EnableCorsAttribute (" ", заголовки: " ", методи: "*", виставленіHeaders: "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();
            }
        }

Я написав це для варіантів. Будь ласка, змініть те саме, що відповідно до вашої потреби.

Щасливе кодування !!


1

Після боротьби цілий вечір я нарешті змусив це попрацювати. Після деякої налагодження я виявив, що проблема, в яку я зайшов, полягала в тому, що мій клієнт надсилає так званий запит перед параметрами перед польотом, щоб перевірити, чи дозволено додатку надсилати поштовий запит із зазначенням походження, методів та заголовків. Я не хотів використовувати Owin або APIController, тому я почав копати і придумав наступне рішення просто з ActionFilterAttribute. Особливо важлива частина "Доступ-контроль-дозволити-заголовки" дуже важлива, оскільки згадані там заголовки мають відповідати заголовкам, які надсилатиме ваш запит.

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));
}

0

В 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>

0

Якщо ви використовуєте 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>

0

Я використовую DotNet Core MVC і після декількох годин боюсь з нульовими пакетами, Startup.cs, атрибутами та цим місцем, я просто додав це до дії MVC:

Response.Headers.Add("Access-Control-Allow-Origin", "*");

Я розумію, що це досить незграбно, але це все, що мені потрібно, і більше нічого не хотілося додати до цих заголовків. Я сподіваюся, що це допомагає комусь іншому!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.