【问题标题】:Access-control-allow-origin with multiple domains具有多个域的访问控制允许来源
【发布时间】:2013-06-23 18:51:33
【问题描述】:

在我的 web.config 中,我想为 access-control-allow-origin 指令指定多个域。我不想使用*。我试过这种语法:

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

这个

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

这个

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

还有这个

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

但它们都不起作用。 什么是正确的语法?

【问题讨论】:

    标签: asp.net iis cors web-config


    【解决方案1】:

    对于 IIS 7.5+ 和 Rewrite 2.0,您可以使用:

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

    解释服务器变量RESPONSE_Access_Control_Allow_Origin部分:
    在 Rewrite 中,您可以在 RESPONSE_ 之后使用任何字符串,它将使用单词的其余部分作为标题名称(在本例中为 Access-Control-Allow-Origin)创建响应标题。重写使用下划线“_”而不是破折号“-”(重写将它们转换为破折号)

    解释服务器变量HTTP_ORIGIN
    同样,在 Rewrite 中,您可以使用 HTTP_ 作为前缀来获取任何请求标头。破折号的规则相同(使用下划线“_”而不是破折号“-”)。

    【讨论】:

    • 您能想出为什么这不适用于 IIS 7.5 的任何原因吗?
    • 我认为应该可以。我指定了 IIS 8.5 版本,因为它是我测试它的地方。
    • @PacoZarate 不错,很棒的提示。要简化为正则表达式并使其更通用,您可以使用 -(http(s)?:\/\/((.+\.)?(domain1|domain2)\.(com|org|net)))。这样您就可以相当轻松地添加其他域并支持多个顶级域(例如 com、org、net 等)。
    • 刚刚在 IIS 7.5 中尝试过。似乎工作得很好。
    • 缓存有问题?调整 web.config 后,我去的第一个网站匹配得很好,但第二个返回的标题与第一个相同。从而导致域不太匹配。
    【解决方案2】:

    Access-Control-Allow-Origin 响应头只能有一个,并且该头只能有一个原始值。因此,为了让它工作,你需要一些代码:

    1. 获取Origin 请求标头。
    2. 检查原始值是否是列入白名单的值之一。
    3. 如果有效,则将Access-Control-Allow-Origin 标头设置为该值。

    我认为没有任何方法可以仅通过 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");
    }
    

    【讨论】:

    • 这回答了我的问题。我不确定为什么微软不允许在 web.config 中指定多个来源......
    • 在哪里可以添加此代码?我有由服务器生成并通过 AJAX 读取的纯文本文件,根本没有代码。我可以将代码放在哪里来限制对我目录中文本文件的访问?
    • @Simon_Weaver 有一个* 值允许任何来源访问资源。然而,最初的问题是关于将一​​组域列入白名单。
    • 因为我是 asp .net 的新手,请问我可以在哪里将这段代码放在我的 asp .net web api 项目中?
    • 为什么你取自 Referrer 标头而不是 Origin 标头?
    【解决方案3】:

    在 Web.API 中可以使用 Microsoft.AspNet.WebApi.Cors 添加此属性,详情请参阅 http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

    在 MVC 中,您可以创建一个过滤器属性来为您完成这项工作:

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

    然后为特定的操作/控制器启用它:

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

    或者为 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
    }
    

    【讨论】:

    • 你知道这适用于哪些版本的 .Net / MVC 吗?
    • 我在 .net 4 / MVC 3 中成功使用了它——据我所知,它应该可以在更高版本中工作,但可能有一种在以后的 MVC 中注册全局过滤器的首选方式版本。
    • 请注意其 WEB API 2 解决方案。不适用于 WEB API 1。
    【解决方案4】:

    在阅读每个答案并尝试之后,他们都没有帮助我。我在其他地方搜索时发现,您可以创建一个自定义属性,然后将其添加到您的控制器中。它会覆盖 EnableCors 并在其中添加列入白名单的域。

    此解决方案运行良好,因为它允许您在 webconfig (appsettings) 中拥有列入白名单的域,而不是在控制器的 EnableCors 属性中对它们进行硬编码。

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

    我在网上找到了这个指南,它的作用就像一个魅力:

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

    我想我会把它放在这里给有需要的人。

    【讨论】:

    • 这是一个仅链接的答案。请让答案独立存在。
    • 好的,我是新来的,这更像是它应该是什么??
    【解决方案5】:

    对于 IIS 7.5+,您可以使用 IIS CORS 模块:https://www.iis.net/downloads/microsoft/iis-cors-module

    你的 web.config 应该是这样的:

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

    您可以在这里找到配置参考:https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference

    【讨论】:

    • 如果它像它所说的那样工作,我希望你在 3 年前发布这个!哇!
    【解决方案6】:

    我按照“monsur”的建议在请求处理代码中解决了这个问题。

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

    【讨论】:

    • 例如,在 webform 中就是这样。只需在可用时使用 Request.Headers。并且,如果需要,使用白名单仅过滤允许的域。
    • 这个就好比在web.config文件中加入
    【解决方案7】:

    查看 Thinktecture IdentityModel 库——它具有完整的 CORS 支持:

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

    它可以动态发出你想要的 ACA-Origin。

    【讨论】:

    • 这似乎是一个非常有用的库。感谢您的链接。
    【解决方案8】:

    您可以将此代码添加到您的 asp.net webapi 项目中

    在文件 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");
        }
    }
    

    【讨论】:

      【解决方案9】:

      试试这个:

      &lt;add name="Access-Control-Allow-Origin" value="['URL1','URL2',...]" /&gt;

      【讨论】:

      • 这种格式是否有任何文档或参考资料?
      • 显示错误“Access-Control-Allow-Origin”标头包含多个值但只允许一个
      【解决方案10】:

      我很幸运地使用了 CORS IIS 插件,您可以从 Microsoft 获得 download。它支持多个域,它允许不同的身份验证配置,并且如果您愿意的话,它允许您只向不同的域提供 API 的子集。

      您只需要在 web.config 中添加这样的部分。

        <system.webServer>
          <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://server1.com"
                    allowCredentials="true"
                    allowed="true"
                    maxAge="120">
            </add>
            <add origin="http://server2.com"
                    allowed="true"
                    allowCredentials="true"
                    maxAge="120">
            </add>
          </cors>
        </system.webServer>
      

      如果您想深入了解选项,请查看here.

      一开始让我感到厌烦的一点是,这与其他 web.config 调整冲突,例如自己手动添加 Access-Control-Origin 标头,所以只做一个或另一个;不是两者都有。

      要注意的另一件事是,即使您的服务器设置完美,您也可能需要进行客户端调整才能实际使用它。例如,这里是 Javascript 获取方法选项,需要用于通过身份验证调用针对 CORS 服务器的方法。

      fetch(url, {
             method: 'GET', // *GET, POST, PUT, DELETE, etc.
             mode: 'cors', // no-cors, *cors, same-origin
             cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
             credentials: 'include', // include, *same-origin, omit
         })
      

      祝你好运。

      【讨论】:

        【解决方案11】:

        您可以使用 owin 中间件来定义 cors 策略,您可以在其中定义多个 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);
                        }
                    }
                };
        

        【讨论】:

          【解决方案12】:

          你只需要:

          • 将 Global.asax 添加到您的项目中,
          • 从您的 web.config 中删除 &lt;add name="Access-Control-Allow-Origin" value="*" /&gt;
          • 之后,在 Global.asax 的 Application_BeginRequest 方法中添加:

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

          我希望这会有所帮助。这对我有用。

          【讨论】:

          • 添加 "...-Origin: *" 有效,除非您允许凭据。如果您将 allow-credentials 设置为 true,那么您必须指定一个域(而不仅仅是 *)。这就是这个问题的症结所在。否则,您只需指定“...allow-credentials: false”即可。
          猜你喜欢
          • 2010-12-11
          相关资源
          最近更新 更多