Access-control-allow-origin con più domini


98

Nel mio web.config vorrei specificare più di un dominio per la access-control-allow-origindirettiva. Non voglio usare *. Ho provato questa sintassi:

<add name="Access-Control-Allow-Origin" value="http://localhost:1506, http://localhost:1502" />

questo

<add name="Access-Control-Allow-Origin" value="http://localhost:1506 http://localhost:1502" />

questo

<add name="Access-Control-Allow-Origin" value="http://localhost:1506; http://localhost:1502" />

e questo

<add name="Access-Control-Allow-Origin" value="http://localhost:1506" />
<add name="Access-Control-Allow-Origin" value="http://localhost:1502" />

ma nessuno di loro funziona. Qual è la sintassi corretta?

Risposte:


78

Può esserci solo Access-Control-Allow-Originun'intestazione di risposta e quell'intestazione può avere solo un valore di origine. Pertanto, affinché funzioni, è necessario disporre di un codice che:

  1. Afferra l' Originintestazione della richiesta.
  2. Controlla se il valore di origine è uno dei valori inseriti nella whitelist.
  3. Se è valido, imposta l' Access-Control-Allow-Originintestazione con quel valore.

Non credo che ci sia alcun modo per farlo esclusivamente tramite web.config.

if (ValidateRequest()) {
    Response.Headers.Remove("Access-Control-Allow-Origin");
    Response.AddHeader("Access-Control-Allow-Origin", Request.UrlReferrer.GetLeftPart(UriPartial.Authority));

    Response.Headers.Remove("Access-Control-Allow-Credentials");
    Response.AddHeader("Access-Control-Allow-Credentials", "true");

    Response.Headers.Remove("Access-Control-Allow-Methods");
    Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
}

2
Questo risponde alla mia domanda. Non sono sicuro del motivo per cui Microsoft non consente di specificare più origini nel web.config però ...
Sam

17
Dove posso aggiungere questo codice? Ho file di testo semplice generati dal server e letti tramite AJAX, nessun codice. Dove posso inserire il codice per limitare l'accesso ai file di testo nella mia directory?
Harry

3
@Simon_Weaver c'è un *valore che consente a qualsiasi origine di accedere alla risorsa. Tuttavia, la domanda originale era relativa all'autorizzazione di un insieme di domini.
monsur

2
dato che sono nuovo di asp .net posso chiedere dove posso inserire questo codice nel mio progetto asp .net web api?
Amrit

93

Per IIS 7.5+ e Rewrite 2.0 puoi usare:

<system.webServer>
   <httpProtocol>
     <customHeaders>
         <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
         <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
     </customHeaders>
   </httpProtocol>
        <rewrite>            
            <outboundRules>
                <clear />                
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?domain1\.com|(.+\.)?domain2\.com|(.+\.)?domain3\.com))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>           
            </outboundRules>
        </rewrite>
 </system.webServer>

Spiegazione della RESPONSE_Access_Control_Allow_Originparte della variabile del server :
In Rewrite puoi usare qualsiasi stringa dopo RESPONSE_e creerà l'intestazione della risposta usando il resto della parola come nome dell'intestazione (in questo caso Access-Control-Allow-Origin). La riscrittura utilizza i trattini bassi "_" invece dei trattini "-" (la riscrittura li converte in trattini)

Spiegazione della variabile del server HTTP_ORIGIN: allo
stesso modo, in Rewrite puoi prendere qualsiasi intestazione della richiesta usando HTTP_come prefisso. Stesse regole con i trattini (usa i trattini bassi "_" invece dei trattini "-").


Riesci a pensare a qualche motivo per cui questo non funzionerebbe con IIS 7.5?
Phil Ricketts

Penso che dovrebbe funzionare. Ho specificato la versione IIS 8.5 perché è lì che l'ho testata.
Paco Zarate

4
@PacoZarate Bello, ottimo suggerimento. Per semplificare la regex e renderla più generica, puoi usare - (http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net))). In questo modo puoi aggiungere altri domini abbastanza facilmente e supportare più domini di primo livello (ad es. Com, org, net ecc.).
Merlin

4
Ho appena provato questo in IIS 7.5. Sembra funzionare bene.
Prescient

2
Hai problemi con la memorizzazione nella cache? Dopo aver modificato il web.config, il primo sito Web in cui vado corrisponde bene, ma il secondo restituisce la stessa intestazione del primo. In questo modo i domini non corrispondono troppo.
Airn5475

20

In Web.API questo attributo può essere aggiunto utilizzando Microsoft.AspNet.WebApi.Corscome descritto in dettaglio su http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

In MVC puoi creare un attributo di filtro per fare questo lavoro per te:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = true, Inherited = true)]
public class EnableCorsAttribute : FilterAttribute, IActionFilter {
    private const string IncomingOriginHeader = "Origin";
    private const string OutgoingOriginHeader = "Access-Control-Allow-Origin";
    private const string OutgoingMethodsHeader = "Access-Control-Allow-Methods";
    private const string OutgoingAgeHeader = "Access-Control-Max-Age";

    public void OnActionExecuted(ActionExecutedContext filterContext) {
        // Do nothing
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var isLocal = filterContext.HttpContext.Request.IsLocal;
        var originHeader = 
             filterContext.HttpContext.Request.Headers.Get(IncomingOriginHeader);
        var response = filterContext.HttpContext.Response;

        if (!String.IsNullOrWhiteSpace(originHeader) &&
            (isLocal || IsAllowedOrigin(originHeader))) {
            response.AddHeader(OutgoingOriginHeader, originHeader);
            response.AddHeader(OutgoingMethodsHeader, "GET,POST,OPTIONS");
            response.AddHeader(OutgoingAgeHeader, "3600");
        }
    }

    protected bool IsAllowedOrigin(string origin) {
        // ** replace with your own logic to check the origin header
        return true;
    }
}

Quindi abilitalo per azioni / controller specifici:

[EnableCors]
public class SecurityController : Controller {
    // *snip*
    [EnableCors]
    public ActionResult SignIn(Guid key, string email, string password) {

Oppure aggiungilo per tutti i controller in Global.asax.cs

protected void Application_Start() {
    // *Snip* any existing code

    // Register global filter
    GlobalFilters.Filters.Add(new EnableCorsAttribute());
    RegisterGlobalFilters(GlobalFilters.Filters);

    // *snip* existing code
}

Sai per quali versioni di .Net / MVC funziona?
Keab42

Lo sto usando con successo in .net 4 / MVC 3 - per quanto ne so dovrebbe funzionare nelle versioni successive, ma potrebbe esserci un modo preferito per registrare il filtro globale nelle versioni successive di MVC.
Rob Church

si prega di notare solo la sua soluzione WEB API 2. non per WEB API 1.
Samih A

5

Dopo aver letto ogni risposta e averle provate, nessuna mi ha aiutato. Quello che ho trovato durante la ricerca altrove è che puoi creare un attributo personalizzato che puoi aggiungere al tuo controller. Sovrascrive quelli di EnableCors e aggiunge i domini autorizzati.

Questa soluzione funziona bene perché ti consente di avere i domini autorizzati nel webconfig (appsettings) invece di codificarli nell'attributo EnableCors sul tuo controller.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsByAppSettingAttribute : Attribute, ICorsPolicyProvider
{
    const string defaultKey = "whiteListDomainCors";
    private readonly string rawOrigins;
    private CorsPolicy corsPolicy;

    /// <summary>
    /// By default uses "cors:AllowedOrigins" AppSetting key
    /// </summary>
    public EnableCorsByAppSettingAttribute()
        : this(defaultKey) // Use default AppSetting key
    {
    }

    /// <summary>
    /// Enables Cross Origin
    /// </summary>
    /// <param name="appSettingKey">AppSetting key that defines valid origins</param>
    public EnableCorsByAppSettingAttribute(string appSettingKey)
    {
        // Collect comma separated origins
        this.rawOrigins = AppSettings.whiteListDomainCors;
        this.BuildCorsPolicy();
    }

    /// <summary>
    /// Build Cors policy
    /// </summary>
    private void BuildCorsPolicy()
    {
        bool allowAnyHeader = String.IsNullOrEmpty(this.Headers) || this.Headers == "*";
        bool allowAnyMethod = String.IsNullOrEmpty(this.Methods) || this.Methods == "*";

        this.corsPolicy = new CorsPolicy
        {
            AllowAnyHeader = allowAnyHeader,
            AllowAnyMethod = allowAnyMethod,
        };

        // Add origins from app setting value
        this.corsPolicy.Origins.AddCommaSeperatedValues(this.rawOrigins);
        this.corsPolicy.Headers.AddCommaSeperatedValues(this.Headers);
        this.corsPolicy.Methods.AddCommaSeperatedValues(this.Methods);
    }

    public string Headers { get; set; }
    public string Methods { get; set; }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,
                                               CancellationToken cancellationToken)
    {
        return Task.FromResult(this.corsPolicy);
    }
}

    internal static class CollectionExtensions
{
    public static void AddCommaSeperatedValues(this ICollection<string> current, string raw)
    {
        if (current == null)
        {
            return;
        }

        var paths = new List<string>(AppSettings.whiteListDomainCors.Split(new char[] { ',' }));
        foreach (var value in paths)
        {
            current.Add(value);
        }
    }
}

Ho trovato questa guida online e ha funzionato a meraviglia:

http://jnye.co/Posts/2032/dynamic-cors-origins-from-appsettings-using-web-api-2-2-cross-origin-support

Ho pensato di lasciarlo qui per chiunque ne avesse bisogno.


Questa è una risposta di solo collegamento. Per favore, fai in modo che la risposta stia da sola.
Ripristina Monica il

1
Ok, sono nuovo qui, è più simile a quello che si suppone sia ??
Helpha

3

Sono riuscito a risolvere questo problema nel codice di gestione delle richieste seguendo i consigli di "monsur".

string origin = WebOperationContext.Current.IncomingRequest.Headers.Get("Origin");

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);

Questo è il modo di fare in webform, ad esempio. Usa semplicemente Request.Headers quando disponibili. E, se necessario, utilizza una whitelist per filtrare solo i domini consentiti.
AFract

3
Ciò
equivale

3

Per IIS 7.5+ è possibile utilizzare il modulo IIS CORS: https://www.iis.net/downloads/microsoft/iis-cors-module

Il tuo web.config dovrebbe essere qualcosa del genere:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://localhost:1506">
                <allowMethods>                    
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
            <add origin="http://localhost:1502">
                <allowMethods>
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
        </cors>
    </system.webServer>
</configuration>

Puoi trovare il riferimento alla configurazione qui: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference


Se funziona come dice, vorrei che l'avessi postato 3 anni fa! Whoa!
Michael,


1

Puoi aggiungere questo codice al tuo progetto webapi asp.net

nel file Global.asax

    protected void Application_BeginRequest()
{
    string origin = Request.Headers.Get("Origin");
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
        Response.StatusCode = 200;
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
    }
}

0

È possibile utilizzare il middleware owin per definire la policy cors in cui è possibile definire più origini cors

return new CorsOptions
        {
            PolicyProvider = new CorsPolicyProvider
            {
                PolicyResolver = context =>
                {
                    var policy = new CorsPolicy()
                    {
                        AllowAnyOrigin = false,
                        AllowAnyMethod = true,
                        AllowAnyHeader = true,
                        SupportsCredentials = true
                    };
                    policy.Origins.Add("http://foo.com");
                    policy.Origins.Add("http://bar.com");
                    return Task.FromResult(policy);
                }
            }
        };

-3

Hai solo bisogno di:

  • aggiungi un Global.asax al tuo progetto,
  • elimina <add name="Access-Control-Allow-Origin" value="*" />dal tuo web.config.
  • in seguito, aggiungi questo nel Application_BeginRequestmetodo di Global.asax:

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
    
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
        HttpContext.Current.Response.End();
    }

Spero che questo aiuto. che funziona per me.


L'aggiunta di "...- Origine: *" funziona tranne quando si consentono le credenziali. Se hai le credenziali di autorizzazione impostate su true, devi specificare un dominio (non semplicemente *). È qui che risiede il nocciolo di questo problema. Altrimenti, potresti semplicemente specificare "... allow-credentials: false" e farla finita.
Richard
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.