Festlegen von Access-Control-Allow-Origin in ASP.Net MVC - einfachste Methode

206

Ich habe eine einfache Aktionsmethode, die etwas json zurückgibt. Es läuft auf ajax.example.com. Ich muss von einer anderen Site someothersite.com darauf zugreifen.

Wenn ich versuche es anzurufen, bekomme ich das erwartete ...:

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

Ich kenne zwei Möglichkeiten, um dies zu umgehen : JSONP und das Erstellen eines benutzerdefinierten HttpHandlers zum Festlegen des Headers.

Gibt es keinen einfacheren Weg?

Ist es für eine einfache Aktion nicht möglich, entweder eine Liste der zulässigen Ursprünge zu definieren - oder einfach alle zuzulassen? Vielleicht ein Aktionsfilter?

Optimal wäre ...:

return json(mydata, JsonBehaviour.IDontCareWhoAccessesMe);
Kjensen
quelle
1
Bitte schauen Sie hier nach vNext und MVC6: neelbhatt40.wordpress.com/2015/09/10/…
Neel

Antworten:

381

Für einfache ASP.NET MVC-Controller

Erstellen Sie ein neues Attribut

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

Kennzeichnen Sie Ihre Aktion:

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

Für die 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);
    }
}

Kennzeichnen Sie einen ganzen API-Controller:

[AllowCrossSiteJson]
public class ValuesController : ApiController
{

Oder einzelne API-Aufrufe:

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

Für Internet Explorer <= v9

IE <= 9 unterstützt CORS nicht. Ich habe ein Javascript geschrieben, das diese Anfragen automatisch über einen Proxy weiterleitet. Es ist alles 100% transparent (Sie müssen nur meinen Proxy und das Skript einschließen).

Laden Sie es mit nuget herunter corsproxyund befolgen Sie die beiliegenden Anweisungen.

Blogbeitrag | Quellcode

jgauffin
quelle
8
Tolle! Ich liebe MVC + U!
Piotr Kula
2
in Ehrfurcht vor der Eleganz dieser Lösung
BraveNewMath
3
Sie können das Attribut problemlos erweitern, um einen bestimmten Ursprung zu akzeptieren, wenn Sie CORS auf Ihre eigenen Domänen beschränken möchten.
Petrus Theron
2
Sie sollten in der Lage sein, dies zu den RegisterHttpFilters in Ihrer App_Start \ FilterConfig hinzuzufügen, richtig? Dies würde es auf alle Api-Controller in Ihrem Projekt anwenden. Wenn Sie dies mit dem obigen Kommentar von pate verbinden, können Sie CORS für alle Controller auf Ihre Domain (s) beschränken.
Bdwakefield
9
Ich habe kürzlich unser Projekt auf MVC 5 aktualisiert und versucht, dies zu tun. Selbst das Hinzufügen des Headers in einem Filter scheint nicht zu funktionieren. Wenn ich die Anforderung im Netzwerk ansehe, ist der Header in der Antwort nicht vorhanden. Gibt es noch etwas, das getan werden muss, damit dies funktioniert?
Kneemin
121

Wenn Sie IIS 7+ verwenden, können Sie eine web.config-Datei im Stammverzeichnis des Ordners im Abschnitt system.webServer ablegen:

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

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

LaundroMatt
quelle
1
Ich kann mich nicht mehr erinnern warum, aber diese Methode funktioniert nicht immer in IIS 7+
LaundroMatt
Hmm. Der einzige Grund, warum ich denken kann, dass es nicht funktionieren würde, ist, wenn eine Anfrage von einem Nicht-CORS-Browser stammt. Aber ich werde weiter nachforschen.
Sellmeadog
29
Dies würde auch die gesamte Website CORS-freundlich machen. Wenn jemand nur eine einzelne Aktion oder einen Controller als CORS-freundlich markieren möchte, ist die akzeptierte Antwort viel besser.
Lev Dubinets
1
Wenn Sie den Abschnitt ASP.Net sehen , wird ein Hinweis angezeigt
Percebus
1
Beim Veröffentlichen meiner App in der SharePoint-Umgebung tritt ein domänenübergreifendes Problem auf. Wenn ich meine App in einer lokalen Umgebung ausführe, läuft meine App einwandfrei. Wenn ich sie jedoch auf Azure auf meiner Sharepoint-Site veröffentliche, wird sie auf die Fehlerseite des Ajax.Begin-Formularaufrufs umgeleitet. Ich habe diese Lösung ausprobiert, aber sie funktioniert bei mir nicht. Gibt es eine andere Alternative dazu?
Jyotsna Wadhwani
22

Ich stieß auf ein Problem, bei dem der Browser sich weigerte, Inhalte bereitzustellen, die er abgerufen hatte, als die Anfrage in Cookies übergeben wurde (z. B. das xhr hatte seine withCredentials=true), und die Site auf Access-Control-Allow-Origineingestellt hatte *. (Der Fehler in Chrome war: "Platzhalter in Access-Control-Allow-Origin kann nicht verwendet werden, wenn das Flag für Anmeldeinformationen wahr ist.")

Aufbauend auf der Antwort von @jgauffin habe ich dies erstellt. Dies ist im Grunde eine Möglichkeit, diese bestimmte Browsersicherheitsprüfung zu umgehen, also Vorbehalt.

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);
    }
}
Ken Smith
quelle
Das war besonders nützlich, danke.
cklimowski
15

Das ist wirklich einfach, fügen Sie dies einfach in web.config hinzu

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

Fügen Sie in Origin alle Domänen ein, die Zugriff auf Ihren Webserver haben, in Header alle möglichen Header, die jede Ajax-HTTP-Anforderung verwenden kann, und in Methoden alle Methoden, die Sie auf Ihrem Server zulassen

Grüße :)

Zvonimir Tokic
quelle
Das Hinzufügen von "Autorisierung" in Access-Control-Allow-Headern kann auch nützlich sein, wenn Sie autorisierte Abfragen verwenden möchten.
Nach dem
9

Manchmal verursacht auch das Verb OPTIONEN Probleme

Einfach: Aktualisieren Sie Ihre web.config wie folgt

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

Und aktualisieren Sie die Webservice / Controller-Header mit httpGet und httpOptions

// GET api/Master/Sync/?version=12121
        [HttpGet][HttpOptions]
        public dynamic Sync(string version) 
        {
Bishoy Hanna
quelle
Übrigens, in Sitefinity müssen Sie * zu den erweiterten Systemeinstellungen im Sicherheitsbereich hinzufügen
Bishoy Hanna
In welchen Dateien muss ich die Controller-Header aktualisieren?
user3281466
5

Fügen Sie diese Zeile Ihrer Methode hinzu, wenn Sie eine API verwenden.

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

Dieses Tutorial ist sehr nützlich. Um eine kurze Zusammenfassung zu geben:

  1. Verwenden Sie das auf Nuget verfügbare CORS-Paket: Install-Package Microsoft.AspNet.WebApi.Cors

  2. Fügen Sie in Ihrer WebApiConfig.csDatei config.EnableCors()der Register()Methode hinzu.

  3. Fügen Sie den Controllern, die Sie für die Verarbeitung von Cors benötigen, ein Attribut hinzu:

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

GrandMasterFlush
quelle
Ich musste diese Methode verwenden, da ich in meiner Anfrage einen benutzerdefinierten Header festlegen musste und die benutzerdefinierte Attributmethode mit der Vorfluganforderung des Browsers nicht funktionierte. Dies scheint in allen Fällen zu funktionieren.
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);
    }
Pranav Labhe
quelle
2

Es gibt verschiedene Möglichkeiten, wie wir die Access-Control-Expose-Header übergeben können.

  • Wie jgauffin erklärt hat, können wir ein neues Attribut erstellen.
  • Wie LaundroMatt erklärt hat, können wir die Datei web.config hinzufügen.
  • Eine andere Möglichkeit besteht darin, Code wie folgt in die Datei webApiconfig.cs einzufügen.

    config.EnableCors (neues EnableCorsAttribute (" ", Header: " ", Methoden: "*", exponierte Header: "TestHeaderToExpose") {SupportsCredentials = true});

Oder wir können den folgenden Code in die Global.Asax-Datei einfügen.

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

Ich habe es für die Optionen geschrieben. Bitte ändern Sie das gleiche nach Ihren Wünschen.

Viel Spaß beim Codieren !!

Trilok Pathak
quelle
1

Nachdem ich einen ganzen Abend gekämpft hatte, brachte ich das endlich zum Laufen. Nach einigem Debuggen stellte ich fest, dass mein Client eine sogenannte Preflight-Optionsanforderung sendete, um zu überprüfen, ob die Anwendung eine Postanforderung mit dem angegebenen Ursprung, den angegebenen Methoden und den angegebenen Headern senden durfte. Ich wollte weder Owin noch einen APIController verwenden, also begann ich zu graben und fand die folgende Lösung mit nur einem ActionFilterAttribute. Insbesondere der Teil "Access-Control-Allow-Headers" ist sehr wichtig, da die dort genannten Header mit den Headern übereinstimmen müssen, die Ihre Anfrage senden wird.

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

Schließlich sieht meine MVC-Aktionsmethode so aus. Wichtig ist hier auch, die Optionen HttpVerbs zu erwähnen, da sonst die Preflight-Anfrage fehlschlägt.

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

Geben Sie in Web.config Folgendes ein

<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>
Elvis Skensberg
quelle
0

Wenn Sie IIS verwenden, würde ich empfehlen, das IIS CORS-Modul auszuprobieren .
Es ist einfach zu konfigurieren und funktioniert für alle Arten von Controllern.

Hier ist ein Beispiel für die Konfiguration:

    <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>
olsh
quelle
0

Ich verwende DotNet Core MVC und nachdem ich einige Stunden mit Nuget-Paketen, Startup.cs, Attributen und diesem Ort gekämpft habe, habe ich dies einfach der MVC-Aktion hinzugefügt:

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

Mir ist klar, dass dies ziemlich klobig ist, aber es ist alles, was ich brauchte, und nichts anderes wollte diese Überschriften hinzufügen. Ich hoffe das hilft jemand anderem!

Ben Power
quelle