具有多个域的访问控制允许来源

时间:2013-06-26 14:46:05

标签: c# asp.net iis web-config cors

在我的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" />

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

12 个答案:

答案 0 :(得分:73)

对于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)创建响应标题。重写使用下划线&#34; _&#34;而不是破折号&#34; - &#34; (重写将它们转换为破折号)

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

答案 1 :(得分:72)

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

  1. 抓取Origin请求标题。
  2. 检查原始值是否为列入白名单的值之一。
  3. 如果有效,请使用该值设置Access-Control-Allow-Origin标题。
  4. 我认为没有办法单独通过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 :(得分:17)

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

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

答案 3 :(得分: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

我以为我会把它放在这里供有需要的人使用。

答案 4 :(得分:3)

我设法根据'monsur'的建议在请求处理代码中解决了这个问题。

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

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

答案 5 :(得分:3)

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

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

229

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

答案 6 :(得分:2)

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

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

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

答案 7 :(得分:1)

尝试一下:

<add name="Access-Control-Allow-Origin" value="['URL1','URL2',...]" />

答案 8 :(得分:1)

我很幸运使用了 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 标头,所以只做一个或另一个;不能两者兼而有之。

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

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

祝你好运。

答案 9 :(得分:0)

您可以使用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);
                }
            }
        };

答案 10 :(得分:0)

您可以将此代码添加到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");
    }
}

答案 11 :(得分:-2)

你只需要: - 为项目添加Global.asax,
- 从web.config中删除 - 在添加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();
}

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