Asp.Net WebApi2 Aktivieren Sie CORS, die nicht mit AspNet.WebApi.Cors funktionieren. 5.2.3

77

Ich habe versucht, die Schritte unter http://enable-cors.org/server_aspnet.html zu befolgen , damit meine RESTful-API (implementiert mit ASP.NET WebAPI2) mit Cross-Origin-Anforderungen (CORS Enabled) funktioniert. Es funktioniert nur, wenn ich die web.config ändere.

Ich habe die WebApi Cors-Abhängigkeit installiert:

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

Dann habe App_Startich in meiner Klasse WebApiConfigwie folgt:

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

Aber nachdem ich die Anwendung ausgeführt habe, fordere ich eine Ressource mit Fiddler an, wie: http: // localhost: 51589 / api / v1 / personen, und in der Antwort kann ich die HTTP-Header nicht sehen, die ich sehen sollte, wie:

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

Vermisse ich einen Schritt? Ich habe es mit folgender Anmerkung auf dem Controller versucht:

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

Gleiches Ergebnis, kein CORS aktiviert.

Wenn ich jedoch Folgendes in meine web.config einfüge (ohne die AspNet.WebApi.Cors-Abhängigkeit zu installieren), funktioniert dies:

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

Jede Hilfe wäre sehr dankbar!

Vielen Dank.

diegosasw
quelle
1
Ich hatte das gleiche Problem, aber ich entschied mich, den Access-Control-Allow-Origin-Header direkt in der Steuerung festzulegen: HttpResponseMessage response = new HttpResponseMessage (HttpStatusCode.OK); // füge bei Bedarf einige Überprüfungen hinzu response.Headers.Add ("Access-Control-Allow-Origin", "*");
Veselin Vasilev

Antworten:

95

Ich habe ein reduziertes Demo-Projekt für Sie erstellt.

Sie können den obigen API-Link von Ihrem lokalen Fiddler aus ausprobieren , um die Header anzuzeigen. Hier ist eine Erklärung.

Global.ascx

Alles was dies tut, ist die WebApiConfig. Es ist nichts als Code-Organisation.

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

WebApiConfig.cs

Die Schlüsselmethode für Ihr hier ist die EnableCrossSiteRequestsMethode. Das ist alles was Sie tun müssen. Das EnableCorsAttributeist ein global scoped CORS - Attribut .

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

Wertecontroller

Die GetMethode erhält das EnableCorsAttribut, das wir global angewendet haben. Die AnotherMethode überschreibt die globale 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

Sie müssen der web.config nichts Besonderes hinzufügen. So sieht die web.config der Demo aus - sie ist leer.

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

Demo

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>

Shaun Luttin
quelle
19
Ich habe alle Schritte von Ihrer Antwort und von hier aus befolgt : asp.net/web-api/overview/security/… . Versuchte verschiedene Kombinationen und nichts aktiviert CORS außer den Web.config-> <customHeaders>Sachen wie in der Frage. Ich verwende die neuesten Pakete (wie in der Frage). Irgendwelche Vorschläge, wo Sie nach dem Problem suchen können? Im Wesentlichen löst dies aus irgendeinem Grund nicht das gleiche Problem für mich.
yǝsʞǝla
9
"Repariert". Aus irgendeinem Grund werden CORS-Header in der Produktion (auf echtem IIS) festgelegt, jedoch nicht auf localhost, wenn sie von VisualStudio ausgeführt werden. Ich weiß nicht warum, ich denke es ist irgendwie bedingt.
yǝsʞǝla
2
Auf meinem lokalen IIS habe ich separate Anwendungen mit unterschiedlichen Portnummern. Shauns Lösung funktionierte ohne den Web.Config-Patch erst ... Ich bemerkte, dass Shaun "*"für die Ursprünge in WebApiConfig verwendet. Also habe ich das "*"In als Ursprung für das EnableCorsAttribute im Controller eingegeben und jetzt funktioniert es ohne die WebConfig. Als ich las, wie man Origins spezifiziert, glaubte ich, dass die Portnummer ungültig war, aber ich bemerkte nicht, dass das "*" in Ordnung war. Außerdem rufen config.EnableCors(cors);die meisten Beispiele ohne den Parameter auf. Zum Beispiel: ( enable-cors.org/server_aspnet.html )
Rob Von Nesselrode
13
Nachdem ich 3 Stunden damit verbracht hatte, es zum Laufen
Webkonfiguration hinzu,
4
@ShaunLuttin Ich glaube, ich habe mich geirrt und es funktioniert tatsächlich. Es scheint, als ob das Framework den Ursprung überprüft und den Header NUR sendet, wenn der Ursprung in der Liste der zulässigen Ursprünge enthalten ist. Wenn der Ursprung nicht in der Liste enthalten ist, sendet das Framework keinen Header (und ich habe dies fälschlicherweise als falsches Verhalten interpretiert, da ich erwartet hatte, dass der zulässige Ursprung für eine Antwort im Header angezeigt wird). Ich werde dies testen und die Ergebnisse berichten.
Aleksei Poliakov
14

Sie müssen nur einige Dateien ändern. Das funktioniert bei mir.

Global.ascx

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

WebApiConfig.cs

Alle Anfragen müssen diesen Code aufrufen.

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

Einige Controller

Nichts zu ändern.

Web.config

Sie müssen Handler in Ihrer web.config hinzufügen

<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>
Jonas Ribeiro
quelle
1
Schließlich war mein Problem die Webkonfiguration
Geomorillo
1
Die Konfigurationsänderung hat den Trick für mich getan. Ich hatte: Handler entfernen ExtensionlessUrlHandler-ISAPI-4.0_32bit ExtensionlessUrlHandler-ISAPI-4.0_64bit ExtensionlessUrlHandler-Integrated-4.0 WebDAV und Handler hinzufügen ExtensionlessUrlHandler-ISAPI-4.0_32bit ExtensionlessUrH Integrated-4.0 ..... Dies führte dazu, dass es nicht funktionierte. Die Änderung gemäß dieser Antwort hat es behoben. danke
biso
13

Im Falle einer CORS-Anfrage antworten alle modernen Browser mit einem OPTION-Verb, und dann folgt die eigentliche Anfrage. Dies soll verwendet werden, um den Benutzer im Falle einer CORS-Anfrage zur Bestätigung aufzufordern. Wenn Sie jedoch im Falle einer API diesen Überprüfungsprozess überspringen möchten, fügen Sie Global.asax das folgende Snippet hinzu

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

Hier bestehen wir nur die Prüfung, indem wir nach dem Verb OPTIONEN suchen.

Neeraj
quelle
1
Vielen Dank. Ist das nicht die Konfiguration auf http-Ebene, mit der sich die Abhängigkeit von Microsoft.AspNet.WebApi.Cors befassen sollte, damit wir sie nicht explizit in unserem Code konfigurieren müssen? Ich kann es funktionieren lassen, indem ich etwas Ähnliches in web.config mache, aber der Punkt ist, Microsoft.AspNet.WebApi.Cors zu verwenden, um damit umzugehen und es Attribut-konfigurierbar zu machen.
Diegosasw
Ich bin mir nicht sicher, warum Sie den Überprüfungsprozess vollständig überspringen möchten. Zumindest nicht in Produktion. Wenn Sie das eingebaute Material so verwenden möchten, wie es entworfen wurde, können Sie CORS ordnungsgemäß konfigurieren und dann das Routing für OPTIONS-Anforderungen ignorieren, wie in meiner Antwort beschrieben
BritishDeveloper
1
Wenn Sie feststellen, dass der IE funktioniert, während Chrome und Firefox ausfallen, ist dies die Lösung. Es hat bei mir in einer Entwicklungsumgebung funktioniert.
Bleeped
@neeraj Nachdem Sie mehrere Dutzend Möglichkeiten ausprobiert haben, ist dies das einzige, was dazu geführt hat, dass es funktioniert. Ist es immer noch eine akzeptable und sichere Methode?
Connie DeCinko
8

Ich habe gerade benutzerdefinierte Header zur Web.config hinzugefügt und es hat wie ein Zauber funktioniert.

Bei der Konfiguration - system.webServer:

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

Ich habe die Frontend-App und das Backend auf der gleichen Lösung. Damit dies funktioniert, muss ich das Webdienstprojekt (Backend) als Standard festlegen, damit dies funktioniert.

Ich habe ReST verwendet und nichts anderes ausprobiert.

Mathter
quelle
Wie andere gesagt haben, verschwendete Zeit damit, es "richtig" zum Laufen zu bringen, und schob es dann einfach in die web.config
Morvael
1
Vielen Dank an @Mathter, dies hat bei mir funktioniert, obwohl CORS über meine Startup-Klasse aktiviert wurde. Die Frage ist jedoch, warum wir dies in web.config einstellen müssen, anstatt es normal zu tun.
Ciaran Gallagher
4

Nach einigen Änderungen in meiner Web.config funktionierte CORS plötzlich nicht mehr in meinem Web API 2-Projekt (zumindest für OPTIONS-Anforderungen während des Preflights). Es scheint, dass Sie den unten genannten Abschnitt in Ihrer Web.config haben müssen, sonst funktioniert das (globale) EnableCorsAttribute nicht für OPTIONS-Anforderungen. Beachten Sie, dass dies genau derselbe Abschnitt ist, den Visual Studio in einem neuen Web API 2-Projekt hinzufügt.

<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>
Christian Gürtler
quelle
2

Keine dieser Antworten funktioniert wirklich. Wie andere angemerkt haben, verwendet das Cors-Paket den Access-Control-Allow-Origin-Header nur, wenn die Anforderung einen Origin-Header hatte. Im Allgemeinen können Sie der Anforderung jedoch nicht einfach einen Origin-Header hinzufügen, da Browser möglicherweise auch versuchen, dies zu regulieren.

Wenn Sie schnell und unkompliziert standortübergreifende Anforderungen an eine Web-API zulassen möchten, ist es viel einfacher, einfach ein benutzerdefiniertes Filterattribut zu schreiben:

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

Verwenden Sie es dann einfach für Ihre Controller-Aktion:

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

Ich werde nicht für die Sicherheit im Allgemeinen bürgen, aber es ist wahrscheinlich viel sicherer als das Setzen der Header in der web.config, da Sie sie auf diese Weise nur so spezifisch anwenden können, wie Sie sie benötigen.

Und natürlich ist es einfach, das oben Gesagte so zu ändern, dass nur bestimmte Ursprünge, Methoden usw. zulässig sind.

Matthew
quelle
Denken Sie nicht, dass dies in der Visual Studio-Debug-Situation funktioniert. Es scheint, dass dieser Code nicht einmal erreicht wird, da der IIS von Visual Studio die Anforderung sogar vor diesem Code verarbeitet.
Ryan
1

Ich habe gerade das gleiche Problem festgestellt und versucht, CORS global zu aktivieren . Ich habe jedoch herausgefunden, dass es funktioniert , jedoch nur, wenn die Anforderung einen OriginHeader-Wert enthält . Wenn Sie den originHeader-Wert weglassen , enthält die Antwort kein Access-Control-Allow-Origin.

Ich habe ein Chrome-Plugin namens DHC verwendet , um meine GET-Anfrage zu testen. Dadurch konnte ich den OriginHeader einfach hinzufügen .

Rick
quelle
1

WEBAPI2: LÖSUNG. global.asax.cs:

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

Klicken Sie im Solution Explorer mit der rechten Maustaste auf das API-Projekt. Setzen Sie im Eigenschaftenfenster 'Anonyme Authentifizierung' auf Aktiviert !!!

Hoffe das hilft jemandem in der Zukunft.

hannes neukermans
quelle
Es gibt keine configin global.asax.cs.
Tala9999
Sollte WebApiConfig.cs sein, in Register ()
HomeMade
1

Niemand mit sicherer Lösung arbeitet für mich, um sicherer als Neeraj und einfacher als Matthew zu sein. Fügen Sie einfach hinzu: System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

In der Methode Ihres Controllers. Diese Arbeit für mich.

public IHttpActionResult Get()
{
    System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    return Ok("value");
}
Puipuix
quelle
Ich habe die CORS-Bibliothek verwendet und das Attribut auf einen Controller gestellt, aber es hat nicht funktioniert. Es hat nur global in WebApiConfig funktioniert. Die Verwendung dieser Lösung funktionierte letztendlich für mich pro Controller. Vielen Dank.
tno2007
0

Ich habe diese Frage gefunden, weil ich Probleme mit der OPTIONS-Anfrage hatte, die die meisten Browser senden. Meine App leitete die OPTIONS-Anforderungen weiter und verwendete mein IoC, um viele Objekte zu erstellen. Einige haben aus verschiedenen Gründen Ausnahmen für diesen ungeraden Anforderungstyp ausgelöst.

Geben Sie im Grunde eine Ignorierroute für alle OPTIONS-Anforderungen ein, wenn diese Probleme verursachen:

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

Weitere Informationen: Stoppen Sie die Verarbeitung von OPTIONS-Anforderungen durch die Web-API

Britischer Entwickler
quelle
0

Hoffe das hilft jemandem in der Zukunft. Mein Problem war, dass ich dem gleichen Tutorial wie das OP folgte, um globales CORS zu aktivieren. Ich habe jedoch auch eine aktionsspezifische CORS-Regel in meiner AccountController.cs-Datei festgelegt:

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

und es wurden Fehler über den Ursprung angezeigt, die nicht null oder eine leere Zeichenfolge sein können. ABER der Fehler trat ausgerechnet in der Datei Global.asax.cs auf. Die Lösung besteht darin, es zu ändern in:

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

Beachten Sie das * in den Ursprüngen? Das Fehlen war der Grund für den Fehler in der Datei Global.asax.cs.

Hoffe das hilft jemandem.

jangooni
quelle