web-dev-qa-db-fra.com

Access-control-allow-Origin avec plusieurs domaines

Dans mon web.config, je voudrais spécifier plusieurs domaines pour la directive access-control-allow-Origin. Je ne veux pas utiliser *. J'ai essayé cette syntaxe:

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

celui-là 

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

celui-là

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

et celui-là

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

mais aucun d'entre eux ne fonctionne ... Quelle est la syntaxe correcte? 

83
Sam

Il ne peut y avoir qu'un seul en-tête de réponse Access-Control-Allow-Origin et cet en-tête ne peut avoir qu'une seule valeur d'origine. Par conséquent, pour que cela fonctionne, vous devez avoir un code qui:

  1. Récupère l'en-tête de la requête Origin.
  2. Vérifie si la valeur Origin est l'une des valeurs de la liste blanche.
  3. S'il est valide, définit l'en-tête Access-Control-Allow-Origin avec cette valeur.

Je ne pense pas qu'il soit possible de le faire uniquement par le biais de 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");
}
70
monsur

Pour IIS 7.5+ et Rewrite 2.0, vous pouvez utiliser:

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

Expliquer la variable serveurRESPONSE_Access_Control_Allow_Originportion:
En réécriture, vous pouvez utiliser n’importe quelle chaîne après le RESPONSE_ et créer l’en-tête de réponse en utilisant le reste du mot comme nom de l’en-tête (dans ce cas, Access-Control-Allow-Origin). La réécriture utilise des traits de soulignement "_" au lieu de tirets "-" (la réécriture les convertit en tirets)

Expliquer la variable serveurHTTP_Origin:
De même, dans Rewrite, vous pouvez récupérer n’importe quel en-tête de requête en utilisant HTTP_ comme préfixe. Mêmes règles avec les tirets (utilisez les soulignés "_" au lieu des tirets "-").

66
Paco Zarate

Dans Web.API, cet attribut peut être ajouté à l'aide de Microsoft.AspNet.WebApi.Cors comme détaillé sur http://www.asp.net/web-api/overview/security/enabling-cross-cross-Origin-requests-in-web- api

Dans MVC, vous pouvez créer un attribut de filtre pour effectuer ce travail à votre place:

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

Ensuite, activez-le pour des actions/contrôleurs spécifiques:

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

Ou ajoutez-le pour tous les contrôleurs dans 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
}
16
Rob Church

Après avoir lu toutes les réponses et les avoir essayées, aucune d’elles ne m’a aidé. Ce que j’ai trouvé lors de recherches ailleurs, c’est que vous pouvez créer un attribut personnalisé que vous pouvez ensuite ajouter à votre contrôleur. Il écrase les noms d'EnableCors et ajoute les domaines de la liste blanche.

Cette solution fonctionne bien, car elle vous permet d’avoir les domaines de la liste blanche dans la configuration Web (appsettings) au lieu de les coder dans l’attribut EnableCors de votre contrôleur.

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

J'ai trouvé ce guide en ligne et cela a fonctionné comme un charme:

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

Je pensais que je laisserais tomber ça ici pour ceux qui sont dans le besoin.

4
Helpha

J'ai réussi à résoudre ce problème dans le code de traitement de la demande en suivant les conseils de «monsur». 

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

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

Regardez dans la bibliothèque Thinktecture IdentityModel - elle supporte complètement CORS:

http://brockallen.com/2012/06/28/cors-support-in-webapi-mvc-and-iis-with-thinktecture-identitymodel/

Et il peut émettre de manière dynamique l’ACA-Origin que vous voulez.

2
Brock Allen

Vous pouvez utiliser le middleware owin pour définir une politique cors dans laquelle vous pouvez définir plusieurs origines 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);
                }
            }
        };
0
chayan banerjee