Asp.Net WebApi2 Увімкнути CORS, що не працює з AspNet.WebApi.Cors 5.2.3


77

Я спробував виконати кроки на веб-сайті http://enable-cors.org/server_aspnet.html, щоб мій RESTful API (реалізований з ASP.NET WebAPI2) працював із запитами про перехресне походження (CORS увімкнено). Це не працює, якщо я не модифікую web.config.

Я встановив залежність WebApi Cors:

install-package Microsoft.AspNet.WebApi.Cors -ProjectName MyProject.Web.Api

Тоді в моєму App_Startкласі WebApiConfigє такий клас :

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var corsAttr = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(corsAttr);

        var constraintsResolver = new DefaultInlineConstraintResolver();

        constraintsResolver.ConstraintMap.Add("apiVersionConstraint", typeof(ApiVersionConstraint));
        config.MapHttpAttributeRoutes(constraintsResolver); 
        config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
        //config.EnableSystemDiagnosticsTracing(); 
        config.Services.Replace(typeof(ITraceWriter), new SimpleTraceWriter(WebContainerManager.Get<ILogManager>())); 
        config.Services.Add(typeof(IExceptionLogger), new SimpleExceptionLogger(WebContainerManager.Get<ILogManager>()));
        config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); 
    }
}

але після цього я запускаю додаток, я запитую у Fiddler такий ресурс, як: http: // localhost: 51589 / api / v1 / persons, і у відповіді я не бачу заголовків HTTP, які я повинен бачити, таких як:

  • Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
  • Access-Control-Allow-Origin: *

Я пропустив якийсь крок? Я спробував із наступною анотацією на контролері:

[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]

Той самий результат, CORS не ввімкнено.

Однак, якщо я додаю наступне у своєму web.config (навіть не встановлюючи залежність AspNet.WebApi.Cors), це працює:

<system.webServer>

<httpProtocol>
  <!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
  <!--
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="content-Type, accept, origin, X-Requested-With, Authorization, name" />
    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
  -->
</httpProtocol>
<handlers>
  <!-- THESE HANDLERS ARE IMPORTANT FOR WEB API TO WORK WITH  GET,HEAD,POST,PUT,DELETE and CORS-->
  <!--

  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,PUT,DELETE" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
-->
</handlers>

Будь-яка допомога буде дуже вдячна!

Дякую.


1
У мене була та ж проблема, але я вирішив встановити заголовок Access-Control-Allow-Origin безпосередньо в контролері: HttpResponseMessage response = new HttpResponseMessage (HttpStatusCode.OK); // додаємо кілька перевірок, якщо потрібно відповідь.Headers.Add ("Access-Control-Allow-Origin", "*");
Веселін Васильєв

Відповіді:


96

Я створив для вас скорочений демонстраційний проект.

Ви можете спробувати наведене вище посилання API у своєму місцевому скрипті, щоб побачити заголовки. Ось пояснення.

Global.ascx

Все це робить виклик WebApiConfig. Це не що інше, як організація коду.

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        WebApiConfig.Register(GlobalConfiguration.Configuration);
    }
}

WebApiConfig.cs

Ключовим методом для вашого тут є EnableCrossSiteRequestsметод. Це все, що вам потрібно зробити. EnableCorsAttributeЄ глобальною областю атрибута CORS .

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
        AddRoutes(config);
    }

    private static void AddRoutes(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Default",
            routeTemplate: "api/{controller}/"
        );
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute(
            origins: "*", 
            headers: "*", 
            methods: "*");
        config.EnableCors(cors);
    }
}

Контролер значень

GetМетод отримує EnableCorsатрибут , який ми застосували в глобальному масштабі. AnotherМетод переопределяет глобальний EnableCors.

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { 
            "This is a CORS response.", 
            "It works from any origin." 
        };
    }

    // GET api/values/another
    [HttpGet]
    [EnableCors(origins:"http://www.bigfont.ca", headers:"*", methods: "*")]
    public IEnumerable<string> Another()
    {
        return new string[] { 
            "This is a CORS response. ", 
            "It works only from two origins: ",
            "1. www.bigfont.ca ",
            "2. the same origin." 
        };
    }
}

Web.config

Вам не потрібно додавати щось особливе у web.config. Насправді так виглядає демонстраційне web.config - воно порожнє.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>

Демо

var url = "https://cors-webapi.azurewebsites.net/api/values"

$.get(url, function(data) {
  console.log("We expect this to succeed.");
  console.log(data);
});

var url = "https://cors-webapi.azurewebsites.net/api/values/another"

$.get(url, function(data) {
  console.log(data);
}).fail(function(xhr, status, text) {
  console.log("We expect this to fail.");
  console.log(status);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


19
Я виконав усі кроки з вашої відповіді та звідси: asp.net/web-api/overview/security/… . Пробували різні комбінації, і ніщо не дозволяє CORS, за винятком Web.config-> <customHeaders>речей, як у питанні. Я використовую останні пакети (так само, як у запитанні). Будь-які пропозиції, де шукати проблему? По суті, чомусь це не вирішує для мене тієї ж проблеми.
yǝsʞǝla

9
"Виправлено". З якоїсь причини він встановлює заголовки CORS у виробництві (на реальному IIS), але не на localhost при запуску з VisualStudio. Не знаю чому, мабуть, це якось умовно.
yǝsʞǝla

2
У моєму локальному IIS у мене є окремі програми з різними номерами портів. Рішення Шона не працювало без виправлення Web.Config до .... Я помітив, що Шон використовує "*"джерела в WebApiConfig. Тож я помістив "*"in як джерело на EnableCorsAttribute у контролері, і тепер воно працює без WebConfig. Я прочитав, як вказати Origins, і привів мене до думки, що номер порту був недійсним, але я не помітив, що "*" було нормальним. Крім того, більшість прикладів викликають config.EnableCors(cors);без параметра. наприклад: ( enable-cors.org/server_aspnet.html )
Роб Фон Нессельроде

13
Після того, як витрачати 3 години , намагаючись змусити його працювати , я просто додав 3 заголовки веб - конфігурації , щоб на самому ділі отримати цю роботу stackoverflow.com/a/21458845/286121
Gyozo kudor

4
@ShaunLuttin Я думаю, що я помилився, і це фактично працює. Здається, що фреймворк перевіряє походження та надсилає заголовок ТІЛЬКИ коли походження знаходиться у списку дозволених джерел. Коли джерела немає у списку, фреймворк не надсилає заголовка (і я помилково інтерпретував це як неправильну поведінку, оскільки я очікував побачити дозволене джерело в заголовку для будь-якої відповіді). Я тестую це і повідомляю результати.
Олексій Поляков

14

Вам просто потрібно змінити деякі файли. Це працює для мене.

Global.ascx

public class WebApiApplication : System.Web.HttpApplication {
    protected void Application_Start()
    {
        WebApiConfig.Register(GlobalConfiguration.Configuration);
    } }

WebApiConfig.cs

Всі запити повинні викликати цей код.

public static class WebApiConfig {
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
        AddRoutes(config);
    }

    private static void AddRoutes(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "Default",
            routeTemplate: "api/{controller}/"
        );
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute(
            origins: "*", 
            headers: "*", 
            methods: "*");
        config.EnableCors(cors);
    } }

Якийсь контролер

Нічого змінити.

Web.config

Вам потрібно додати обробники у свій web.config

<configuration> 
  <system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>   
  </system.webServer> 
</configuration>

1
нарешті, моєю проблемою стала
webconfig

1
Зміна конфігурації зробила для мене фокус .. у мене було: видалити обробники ExtensionlessUrlHandler-ISAPI-4.0_32bit ExtensionlessUrlHandler-ISAPI-4.0_64bit ExtensionlessUrlHandler-Integrated-4.0 WebDAV та додати обробники ExtensionlessUrlHandler-ISAPI-4.0_32bitAPH Extension-UI Integrated-4.0 ..... Це призвело до того, що він не працював .. зміна відповідно до цієї відповіді це виправило. спасибі
biso

13

У разі запиту CORS усі сучасні браузери відповідають дієсловом OPTION, і тоді фактичний запит прослідковується. Це має використовуватися для запиту користувача про підтвердження у разі запиту CORS. Але у випадку API, якщо ви хочете пропустити цей процес перевірки, додайте такий фрагмент до Global.asax

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }

Тут ми просто передаємо перевірку, перевіряючи дієслово OPTIONS.


1
Дякуємо, хіба не з цією конфігурацією рівня http має займатись залежність Microsoft.AspNet.WebApi.Cors, щоб нам не потрібно було явно її конфігурувати в нашому коді? Я можу змусити його працювати, роблячи щось подібне в web.config, але суть у тому, щоб використовувати Microsoft.AspNet.WebApi.Cors, щоб мати справу з цим і мати його атрибут, що налаштовується.
diegosasw

Не знаю, чому ви хочете повністю пропустити процес перевірки. Принаймні не у виробництві. Якщо ви хочете використовувати вбудовані матеріали, як вони були розроблені, ви можете правильно налаштувати CORS, а потім ігнорувати маршрутизацію запитів OPTIONS, як це детально описано в моїй відповіді
BritishDeveloper

1
Якщо ви виявите, що IE працює, поки Chrome і Firefox не працюють, це цілком може бути рішенням. Це спрацювало для мене в середовищі розробки.
Очищений

@neeraj Спробувавши кілька десятків способів, це єдине, що змусило його працювати. Чи все-таки це прийнятний та безпечний метод?
Конні Дечінко,

8

Я щойно додав власні заголовки до Web.config, і це спрацювало як шарм.

На конфігурації - system.webServer:

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
  </customHeaders>
</httpProtocol>

У мене інтерфейсний додаток і серверний сервер на тому ж рішенні. Щоб це працювало, мені потрібно встановити проект веб-служб (Backend) за замовчуванням, щоб це працювало.

Я використовував ReST, не пробував ні з чим іншим.


Як вже говорили інші, марно витрачали час на спроби змусити його працювати "належним чином", а потім просто
засунули

1
Дякую @Mathter, це спрацювало для мене, незважаючи на те, що ввімкнув CORS через мій клас запуску. Питання, однак, чому нам доводиться встановлювати це в web.config, а не робити це звичайним способом?
Ciaran Gallagher

4

Після деяких модифікацій у моєму Web.config CORS раптово припинив роботу в моєму проекті Web API 2 (принаймні для запиту OPTIONS під час попередньої перевірки). Здається, вам потрібно мати розділ, згаданий нижче, у вашому Web.config, інакше (глобальний) EnableCorsAttribute не працюватиме на запити OPTIONS. Зверніть увагу, що це точно той самий розділ, який Visual Studio додасть у новий проект Web API 2.

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
    <remove name="OPTIONSVerbHandler"/>
    <remove name="TRACEVerbHandler"/>
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
  </handlers>
</system.webServer>

2

Жодна з цих відповідей насправді не працює. Як зазначали інші, пакет Cors використовуватиме заголовок Access-Control-Allow-Origin, лише якщо запит мав заголовок Origin. Але загалом ви не можете просто додати до запиту заголовок Origin, оскільки браузери можуть спробувати регулювати це теж.

Якщо ви хочете швидкий і брудний спосіб дозволити запити між сайтами до веб-API, насправді набагато простіше просто написати власний атрибут фільтра:

public class AllowCors : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext == null)
        {
            throw new ArgumentNullException("actionExecutedContext");
        }
        else
        {
            actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Origin");
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        }
        base.OnActionExecuted(actionExecutedContext);
    }
}

Тоді просто використовуйте його для дії контролера:

[AllowCors]
public IHttpActionResult Get()
{
    return Ok("value");
}

Я не поручуся за безпеку цього в цілому, але це, мабуть, набагато безпечніше, ніж встановлювати заголовки в web.config, оскільки таким чином ви можете застосовувати їх лише настільки конкретно, наскільки вони вам потрібні.

І, звичайно, просто змінити вищезазначене, дозволяючи лише певні джерела, методи тощо.


Не думайте, що це працює у ситуації налагодження Visual Studio. Здається, цього коду навіть не вдається досягти, оскільки Visual Studio IIS навіть приймає запит до цього коду.
Райан

1

Я щойно випробував цю саму проблему, намагаючись увімкнути CORS у всьому світі . Однак я виявив, що це працює, проте лише тоді, коли запит містить Originзначення заголовка. Якщо опустити originзначення заголовка, відповідь не міститиме а Access-Control-Allow-Origin.

Я використав плагін chrome під назвою DHC, щоб перевірити свій запит на GET. Це дозволило мені легко додати Originзаголовок.


1

WEBAPI2: РІШЕННЯ. global.asax.cs:

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

У досліднику рішень клацніть правою кнопкою миші api-проект. У вікні властивостей встановіть «Анонімну автентифікацію» на « Увімкнено» !!!

Сподіваюся, це допоможе комусь у майбутньому.


У configglobal.asax.cs немає .
tala9999

Має бути WebApiConfig.cs, всередині Register ()
HomeMade

1

Ніхто з безпечних рішень не працює для мене, щоб бути безпечнішим за Ніраджа та легшим за Метью, просто додайте: System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

У методі вашого контролера. Це працює для мене.

public IHttpActionResult Get()
{
    System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    return Ok("value");
}

Я використав бібліотеку CORS і поставив атрибут на контролер, але він не спрацював. Тільки глобально використовуючи його всередині WebApiConfig, це спрацювало. Використання цього рішення врешті-решт працювало для мене на основі контролера. Дякую.
tno2007

0

Я знайшов це запитання, оскільки у мене виникли проблеми із запитом OPTIONS, який надсилає більшість браузерів. Моя програма маршрутизувала запити OPTIONS та використовувала мій IoC для побудови безлічі об’єктів, а деякі з різних причин кидали винятки для цього непарного типу запиту.

В основному вкладіть ігнорувати маршрут для всіх запитів OPTIONS, якщо вони викликають у вас проблеми:

var constraints = new { httpMethod = new HttpMethodConstraint(HttpMethod.Options) };
config.Routes.IgnoreRoute("OPTIONS", "{*pathInfo}", constraints);

Докладніше: Зупинити обробку запитів OPTIONS за допомогою веб-API


0

Сподіваюся, це допоможе комусь у майбутньому. Моя проблема полягала в тому, що я дотримувався того самого підручника, що і OP, щоб увімкнути глобальну CORS. Однак я також встановив правило CORS для конкретного дії у своєму файлі AccountController.cs:

[EnableCors(origins: "", headers: "*", methods: "*")]

і отримував помилки щодо походження, не може бути нульовим або порожнім рядком. АЛЕ помилка траплялася у файлі Global.asax.cs усіх місць. Рішення полягає в тому, щоб змінити його на:

[EnableCors(origins: "*", headers: "*", methods: "*")]

помічаєте * у витоках? Відсутність саме цього спричинила помилку у файлі Global.asax.cs.

Сподіваюся, це комусь допомагає.

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