Ustawianie kontroli dostępu-Allow-Origin w ASP.Net MVC - najprostsza możliwa metoda


206

Mam prostą metodę działania, która zwraca trochę JSON. Działa na ajax.example.com. Potrzebuję uzyskać dostęp do tego z innej witryny someothersite.com.

Jeśli spróbuję to nazwać, otrzymuję oczekiwane ...:

Origin http://someothersite.com is not allowed by Access-Control-Allow-Origin.

Znam dwa sposoby obejścia tego: JSONP i utworzenie niestandardowego HttpHandler w celu ustawienia nagłówka.

Czy nie ma prostszego sposobu?

Czy nie jest możliwe proste działanie, aby zdefiniować listę dozwolonych źródeł - lub po prostu zezwolić wszystkim? Może filtr akcji?

Optymalne byłoby ...:

return json(mydata, JsonBehaviour.IDontCareWhoAccessesMe);

1
Proszę spojrzeć tutaj na vNext i MVC6: neelbhatt40.wordpress.com/2015/09/10/…
— Neel

Odpowiedzi:


381

Dla zwykłych kontrolerów ASP.NET MVC

Utwórz nowy atrybut

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
        base.OnActionExecuting(filterContext);
    }
}

Oznacz swoją akcję:

[AllowCrossSiteJson]
public ActionResult YourMethod()
{
    return Json("Works better?");
}

Dla interfejsu API sieci Web 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);
    }
}

Oznacz cały kontroler API:

[AllowCrossSiteJson]
public class ValuesController : ApiController
{

Lub indywidualne wywołania API:

[AllowCrossSiteJson]
public IEnumerable<PartViewModel> Get()
{
    ...
}

Dla Internet Explorera <= v9

IE <= 9 nie obsługuje CORS. Napisałem javascript, który automatycznie przekieruje te żądania przez serwer proxy. Wszystko jest w 100% przejrzyste (wystarczy podać mój serwer proxy i skrypt).

Pobierz go za pomocą nugetu corsproxyi postępuj zgodnie z dołączonymi instrukcjami.

Wpis na blogu | Kod źródłowy


8
Niesamowity! I luv MVC + U!
— Piotr Kula,

2
pod wrażeniem elegancji tego rozwiązania
— BraveNewMath,

3
Możesz z łatwością rozszerzyć atrybut, aby zaakceptować określone pochodzenie, jeśli chcesz ograniczyć CORS do własnych domen.
— Petrus Theron

2
Powinieneś być w stanie dodać to do RegisterHttpFilters w App_Start \ FilterConfig, prawda? Spowodowałoby to zastosowanie go do wszystkich kontrolerów API w projekcie. Łącząc to z komentarzem Pate powyżej, możesz ograniczyć CORS do swojej domeny (domen) dla wszystkich kontrolerów.
— bdwakefield

9
Niedawno zaktualizowałem nasz projekt do MVC 5 i próbowałem to zrobić. Nawet dodanie nagłówka w filtrze nie działa. Kiedy przeglądam żądanie w sieci, w odpowiedzi nie ma nagłówka. Czy jest coś jeszcze, co należy zrobić, aby to zadziałało?
— Kneemin

121

Jeśli używasz IIS 7+, możesz umieścić plik web.config w katalogu głównym folderu, korzystając z tego w sekcji system.webServer:

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

Zobacz: http://msdn.microsoft.com/en-us/library/ms178685.aspx I: http://enable-cors.org/#how-iis7


1
Nie pamiętam już, dlaczego, ale ta metoda nie zawsze działa w IIS 7+
— LaundroMatt

Hmm Jedyny powód, dla którego mogę pomyśleć, że to nie zadziała, jeśli żądanie pochodzi z przeglądarki innej niż CORS. Ale będę kontynuować śledztwo.
— sellmeadog

29
Dzięki temu cała strona będzie przyjazna dla CORS. Jeśli ktoś chce oznaczyć tylko jedną akcję lub kontroler jako przyjazny dla CORS, wówczas zaakceptowana odpowiedź jest znacznie lepsza.
— Lev Dubinets,

1
Jeśli zobaczysz sekcję ASP.Net , zawiera ona podpowiedź : „Uwaga: to podejście jest zgodne z IIS6, IIS7 Classic Mode i IIS7 Integrated Mode”.
— dostbus

1
Podczas publikowania aplikacji w środowisku SharePoint mam do czynienia z problemem między domenami. Kiedy uruchamiam moją aplikację w środowisku lokalnym, moja aplikacja działa poprawnie, ale kiedy publikuję ją na lazurach w mojej witrynie Sharepoint, przekierowuje do strony błędów w wywołaniu formularza Ajax.Begin. Wypróbowałem to rozwiązanie, ale nie działa dla mnie. Czy jest jakaś inna alternatywa?
— Jyotsna Wadhwani,

22

Natknąłem się na problem polegający na tym, że przeglądarka odmówiła podania treści, którą pobrała, gdy żądanie przeszło w plikach cookie (np. Xhr miał swoją withCredentials=true), a witryna została Access-Control-Allow-Originustawiona *. (Błąd w Chrome brzmiał: „Nie można użyć symboli wieloznacznych w Access-Control-Allow-Origin, gdy flaga poświadczeń jest prawdziwa”).

Opierając się na odpowiedzi z @jgauffin, stworzyłem to, co jest w zasadzie sposobem obejścia tego konkretnego sprawdzenia bezpieczeństwa przeglądarki, więc zastrzegaj 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);
    }
}

To było szczególnie przydatne, dziękuję.
— cklimowski

15

To jest naprawdę proste, po prostu dodaj to w 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>

W Origin umieść wszystkie domeny, które mają dostęp do twojego serwera WWW, w nagłówkach umieść wszystkie możliwe nagłówki, których może użyć każde żądanie HTTP w ajax, w metodach umieść wszystkie metody, na które zezwolisz na serwerze

pozdrowienia :)


Dodanie „Autoryzacji” w nagłówkach Kontrola dostępu-Zezwalaj może być również przydatne, jeśli zamierzasz używać zapytań autoryzowanych.
— AFract

9

Czasami OPCJE czasownik również powoduje problemy

Po prostu: zaktualizuj plik web.config za pomocą następujących elementów

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

I zaktualizuj nagłówki usługi internetowej / kontrolera za pomocą httpGet i httpOptions

// GET api/Master/Sync/?version=12121
        [HttpGet][HttpOptions]
        public dynamic Sync(string version) 
        {

BTW, w sitefinity musisz dodać * do zaawansowanych ustawień systemu w sekcji bezpieczeństwa
— Bishoy Hanna

w jakich plikach muszę zaktualizować nagłówki kontrolera?
— user3281466,


5

Dodaj ten wiersz do metody, jeśli używasz interfejsu API.

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

4

Ten samouczek jest bardzo przydatny. Aby podać krótkie podsumowanie:

  1. Skorzystaj z pakietu CORS dostępnego w Nuget: Install-Package Microsoft.AspNet.WebApi.Cors

  2. W swoim WebApiConfig.cspliku dodaj config.EnableCors()do Register()metody.

  3. Dodaj atrybut do kontrolerów, których potrzebujesz do obsługi corsów:

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


Musiałem użyć tej metody, ponieważ musiałem ustawić niestandardowy nagłówek w moim żądaniu, a metoda niestandardowego atrybutu nie działała z żądaniem przed lotem przeglądarki. Wydaje się, że działa to we wszystkich przypadkach.
— 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

Istnieją różne sposoby przekazywania nagłówków kontroli dostępu i kontroli dostępu.

  • Jak wyjaśnił jgauffin, możemy utworzyć nowy atrybut.
  • Jak wyjaśnił LaundroMatt, możemy dodać plik web.config.
  • Innym sposobem jest dodanie kodu jak poniżej w pliku webApiconfig.cs.

    config.EnableCors (nowe EnableCorsAttribute („ ”, nagłówki: „ ”, metody: „*”, odsłonięte nagłówki: „TestHeaderToExpose”) {SupportsCredentials = true});

Lub możemy dodać poniższy kod w pliku 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();
            }
        }

Napisałem to dla opcji. Proszę zmodyfikować to samo, jak na swoje potrzeby.

Happy Coding !!


1

Po całym zmaganiu przez cały wieczór w końcu udało mi się to uruchomić. Po pewnym debugowaniu odkryłem, że problem, w który wchodzę, polegał na tym, że mój klient wysyłał tak zwane żądanie opcji inspekcji wstępnej, aby sprawdzić, czy aplikacja może wysłać żądanie postu z podaniem źródła, metod i nagłówków. Nie chciałem używać Owina ani kontrolera APIC, więc zacząłem kopać i wymyśliłem następujące rozwiązanie z tylko ActionFilterAttribute. Szczególnie ważna jest część „Kontrola dostępu - Zezwalaj na nagłówki”, ponieważ wspomniane tam nagłówki muszą pasować do nagłówków, które wyśle ​​twoje zapytanie.

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

Wreszcie moja metoda akcji MVC wygląda następująco. Ważne jest również wspomnienie o Opcjach HttpVerbs, ponieważ w przeciwnym razie żądanie inspekcji wstępnej zakończy się niepowodzeniem.

[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Options)]
[AllowCrossSiteJson]
public async Task<ActionResult> Create(MyModel model)
{
    return Json(await DoSomething(model));
}

0

W Web.config wprowadź następujące dane

<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

Jeśli używasz IIS, sugeruję wypróbowanie modułu CORS IIS .
Jest łatwy w konfiguracji i działa na wszystkich typach kontrolerów.

Oto przykład konfiguracji:

    <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

Używam DotNet Core MVC i po kilku godzinach walki z pakietami nuget, Startup.cs, atrybutami i tym miejscem, po prostu dodałem to do akcji MVC:

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

Zdaję sobie sprawę, że jest to dość niezręczne, ale to wszystko, czego potrzebowałem i nic więcej nie chciałem dodawać tych nagłówków. Mam nadzieję, że to pomaga komuś innemu!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.