配置cors以允许所有使用ASP.NET Core的子域(Asp.net 5,MVC6,VNext)

时间:2016-04-26 23:34:11

标签: asp.net-core cors asp.net-core-mvc

我在ASP.NET Core Web应用程序中正确设置了cors。我使用以下包...

"Microsoft.AspNet.Cors": "6.0.0-rc1-final"

这是startup.cs片段......

public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddCors
    (
        options =>
        {
            options.AddPolicy
            (
                CORSDefaults.PolicyName, 
                builder =>
                {
                    //From config...
                    var allowedDomains = new []{"http://aaa.somewhere.com","https://aaa.somewhere.com","http://bbb.somewhere.com","https://bbb.somewhere.com"};

                    //Load it
                    builder
                        .WithOrigins(allowedDomains)
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                }
            );
        }
    );
}

除了要允许的子域列表快速增长并且我想允许“somewhere.com”的所有子域之外,这很有用。像“* .somewhere.com”之类的东西。我似乎无法在新的ASP.NET Core(MVC6,ASP.NET5,VNext)中找到有关如何执行此操作的任何文档。我发现的所有演示如何执行此操作的文档/示例都适用于早期版本的MVC或WebApi。如何在新堆栈中实现这一目标?

5 个答案:

答案 0 :(得分:30)

现在已在2.0.0版中实现。在<div class="page_list_container"> <div class="row-lister"> <div class="column1"> <span class="lister"><img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /></span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here Long description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here..... This is also a bit longer</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here longer a bit ...</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> <div class="row-lister"> <div class="column1"> <span class="lister"> <img class="page-list-img" src="https://vignette.wikia.nocookie.net/shararam-smeshi/images/1/1c/CSS.png/revision/latest?cb=20161102175256&path-prefix=ru" /> </span> </div> <div class="column2"> <table> <tbody> <tr> <td> <h4>Title</h4> <em>Description here</em> <p class="button-page-list-p"><a href="" title="Bone fixation devices">Find out more</a></p> </td> </tr> </tbody> </table> </div> </div> </div>中使用以下内容:

ConfigureServices

此外,请不要忘记在options.AddPolicy("MyCorsPolicy", builder => builder .SetIsOriginAllowedToAllowWildcardSubdomains() .WithOrigins("https://*.mydomain.com") .AllowAnyMethod() .AllowCredentials() .AllowAnyHeader() .Build() ); 电话中拨打UseCors:

Configure

答案 1 :(得分:16)

我{ASP.NET}团队submitted a pull request进行此更改,希望它能够进入nuget包。在那之前,我使用此解决方法。

下面你像往常一样注册cors,但必须在di容器中注册WildCardCorsService类。

public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.TryAdd(ServiceDescriptor.Transient<ICorsService, WildCardCorsService>());
    services.AddCors
    (
        options =>
        {
            options.AddPolicy
            (
                CORSDefaults.PolicyName, 
                builder =>
                {
                    builder
                        .WithOrigins("http://*.withwildcardsubdomain.com", "http://nowildcard.com")
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                }
            );
        }
    );
}

在解决方案中本地保存此类。它是Microsoft.AspNet.Cors.CorsService.cs类的复制和编辑,以允许它处理通配符子域。如果它找到了一个通配符&#39; *&#39;它将检查根域是否与允许的原点和实际原点匹配。它不支持部分通配符匹配。

namespace Microsoft.AspNet.Cors.Infrastructure
{
    /// <summary>
    /// This ICorsService should be used in place of the official default CorsService to support origins 
    /// like http://*.example.comwhich will allow any subdomain for example.com
    /// </summary>
    public class WildCardCorsService : ICorsService
    {
        private readonly CorsOptions _options;

        /// <summary>
        /// Creates a new instance of the <see cref="CorsService"/>.
        /// </summary>
        /// <param name="options">The option model representing <see cref="CorsOptions"/>.</param>
        public WildCardCorsService(IOptions<CorsOptions> options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            _options = options.Value;
        }

        /// <summary>
        /// Looks up a policy using the <paramref name="policyName"/> and then evaluates the policy using the passed in
        /// <paramref name="context"/>.
        /// </summary>
        /// <param name="requestContext"></param>
        /// <param name="policyName"></param>
        /// <returns>A <see cref="CorsResult"/> which contains the result of policy evaluation and can be
        /// used by the caller to set appropriate response headers.</returns>
        public CorsResult EvaluatePolicy(HttpContext context, string policyName)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var policy = _options.GetPolicy(policyName);
            return EvaluatePolicy(context, policy);
        }

        /// <inheritdoc />
        public CorsResult EvaluatePolicy(HttpContext context, CorsPolicy policy)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (policy == null)
            {
                throw new ArgumentNullException(nameof(policy));
            }

            var corsResult = new CorsResult();
            var accessControlRequestMethod = context.Request.Headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlRequestMethod];
            if (string.Equals(context.Request.Method, Microsoft.AspNet.Cors.Infrastructure.CorsConstants.PreflightHttpMethod, StringComparison.Ordinal) &&
                !StringValues.IsNullOrEmpty(accessControlRequestMethod))
            {
                EvaluatePreflightRequest(context, policy, corsResult);
            }
            else
            {
                EvaluateRequest(context, policy, corsResult);
            }

            return corsResult;
        }

        public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result)
        {
            var origin = context.Request.Headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.Origin];
            if (!OriginIsAllowed(origin, policy))
            {
                return;
            }

            AddOriginToResult(origin, policy, result);
            result.SupportsCredentials = policy.SupportsCredentials;
            AddHeaderValues(result.AllowedExposedHeaders, policy.ExposedHeaders);
        }

        public virtual void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result)
        {
            var origin = context.Request.Headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.Origin];
            if (!OriginIsAllowed(origin, policy))
            {
                return;
            }

            var accessControlRequestMethod = context.Request.Headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlRequestMethod];
            if (StringValues.IsNullOrEmpty(accessControlRequestMethod))
            {
                return;
            }

            var requestHeaders =
                context.Request.Headers.GetCommaSeparatedValues(Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlRequestHeaders);

            if (!policy.AllowAnyMethod && !policy.Methods.Contains(accessControlRequestMethod))
            {
                return;
            }

            if (!policy.AllowAnyHeader &&
                requestHeaders != null &&
                !requestHeaders.All(header => Microsoft.AspNet.Cors.Infrastructure.CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase) ||
                                              policy.Headers.Contains(header, StringComparer.OrdinalIgnoreCase)))
            {
                return;
            }

            AddOriginToResult(origin, policy, result);
            result.SupportsCredentials = policy.SupportsCredentials;
            result.PreflightMaxAge = policy.PreflightMaxAge;
            result.AllowedMethods.Add(accessControlRequestMethod);
            AddHeaderValues(result.AllowedHeaders, requestHeaders);
        }

        /// <inheritdoc />
        public virtual void ApplyResult(CorsResult result, HttpResponse response)
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            var headers = response.Headers;

            if (result.AllowedOrigin != null)
            {
                headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlAllowOrigin] = result.AllowedOrigin;
            }

            if (result.VaryByOrigin)
            {
                headers["Vary"] = "Origin";
            }

            if (result.SupportsCredentials)
            {
                headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlAllowCredentials] = "true";
            }

            if (result.AllowedMethods.Count > 0)
            {
                // Filter out simple methods
                var nonSimpleAllowMethods = result.AllowedMethods
                    .Where(m =>
                        !Microsoft.AspNet.Cors.Infrastructure.CorsConstants.SimpleMethods.Contains(m, StringComparer.OrdinalIgnoreCase))
                    .ToArray();

                if (nonSimpleAllowMethods.Length > 0)
                {
                    headers.SetCommaSeparatedValues(
                        Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlAllowMethods,
                        nonSimpleAllowMethods);
                }
            }

            if (result.AllowedHeaders.Count > 0)
            {
                // Filter out simple request headers
                var nonSimpleAllowRequestHeaders = result.AllowedHeaders
                    .Where(header =>
                        !Microsoft.AspNet.Cors.Infrastructure.CorsConstants.SimpleRequestHeaders.Contains(header, StringComparer.OrdinalIgnoreCase))
                    .ToArray();

                if (nonSimpleAllowRequestHeaders.Length > 0)
                {
                    headers.SetCommaSeparatedValues(
                        Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlAllowHeaders,
                        nonSimpleAllowRequestHeaders);
                }
            }

            if (result.AllowedExposedHeaders.Count > 0)
            {
                // Filter out simple response headers
                var nonSimpleAllowResponseHeaders = result.AllowedExposedHeaders
                    .Where(header =>
                        !Microsoft.AspNet.Cors.Infrastructure.CorsConstants.SimpleResponseHeaders.Contains(header, StringComparer.OrdinalIgnoreCase))
                    .ToArray();

                if (nonSimpleAllowResponseHeaders.Length > 0)
                {
                    headers.SetCommaSeparatedValues(
                        Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlExposeHeaders,
                        nonSimpleAllowResponseHeaders);
                }
            }

            if (result.PreflightMaxAge.HasValue)
            {
                headers[Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AccessControlMaxAge]
                    = result.PreflightMaxAge.Value.TotalSeconds.ToString(CultureInfo.InvariantCulture);
            }
        }

        protected virtual bool OriginIsAllowed(string origin, CorsPolicy policy)
        {
            if (!string.IsNullOrWhiteSpace(origin) &&
                (policy.AllowAnyOrigin ||
                 policy.Origins.Contains(origin) ||
                 IsWildCardSubdomainMatch(origin, policy)))
                return true;

            return false;
        }

        private void AddOriginToResult(string origin, CorsPolicy policy, CorsResult result)
        {
            if (policy.AllowAnyOrigin)
            {
                if (policy.SupportsCredentials)
                {
                    result.AllowedOrigin = origin;
                    result.VaryByOrigin = true;
                }
                else
                {
                    result.AllowedOrigin = Microsoft.AspNet.Cors.Infrastructure.CorsConstants.AnyOrigin;
                }
            }
            else
            {
                result.AllowedOrigin = origin;
            }
        }

        private static void AddHeaderValues(IList<string> target, IEnumerable<string> headerValues)
        {
            if (headerValues == null)
            {
                return;
            }

            foreach (var current in headerValues)
            {
                target.Add(current);
            }
        }

        private bool IsWildCardSubdomainMatch(string origin, CorsPolicy policy)
        {
            var actualOriginUri = new Uri(origin);
            var actualOriginRootDomain = GetRootDomain(actualOriginUri);

            foreach (var o in policy.Origins)
            {
                if (!o.Contains("*"))
                    continue;

                // 1) CANNOT USE System.Text.RegularExpression since it does not exist in .net platform 5.4 (which the Microsoft.AspNet.Cors project.json targets)
                // 2) '*' char is not valid for creation of a URI object so we replace it just for this comparison
                var allowedOriginUri = new Uri(o.Replace("*", "SOMELETTERS"));
                if (allowedOriginUri.Scheme == actualOriginUri.Scheme &&
                    actualOriginRootDomain == GetRootDomain(allowedOriginUri))
                    return true;
            }

            return false;
        }

        private string GetRootDomain(Uri uri)
        {
            //Got this snippet here http://stackoverflow.com/questions/16473838/get-domain-name-of-a-url-in-c-sharp-net
            var host = uri.Host;
            int index = host.LastIndexOf('.'), last = 3;

            while (index > 0 && index >= last - 3)
            {
                last = index;
                index = host.LastIndexOf('.', last - 1);
            }

            return host.Substring(index + 1);
        }
    }

    /// <summary>
    /// Needed to copy these in since some of them are internal to the Microsoft.AspNet.Cors project
    /// </summary>
    public static class CorsConstants
    {
        /// <summary>The HTTP method for the CORS preflight request.</summary>
        public static readonly string PreflightHttpMethod = "OPTIONS";
        /// <summary>The Origin request header.</summary>
        public static readonly string Origin = "Origin";
        /// <summary>
        /// The value for the Access-Control-Allow-Origin response header to allow all origins.
        /// </summary>
        public static readonly string AnyOrigin = "*";
        /// <summary>The Access-Control-Request-Method request header.</summary>
        public static readonly string AccessControlRequestMethod = "Access-Control-Request-Method";
        /// <summary>The Access-Control-Request-Headers request header.</summary>
        public static readonly string AccessControlRequestHeaders = "Access-Control-Request-Headers";
        /// <summary>The Access-Control-Allow-Origin response header.</summary>
        public static readonly string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
        /// <summary>The Access-Control-Allow-Headers response header.</summary>
        public static readonly string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
        /// <summary>The Access-Control-Expose-Headers response header.</summary>
        public static readonly string AccessControlExposeHeaders = "Access-Control-Expose-Headers";
        /// <summary>The Access-Control-Allow-Methods response header.</summary>
        public static readonly string AccessControlAllowMethods = "Access-Control-Allow-Methods";
        /// <summary>The Access-Control-Allow-Credentials response header.</summary>
        public static readonly string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
        /// <summary>The Access-Control-Max-Age response header.</summary>
        public static readonly string AccessControlMaxAge = "Access-Control-Max-Age";
        internal static readonly string[] SimpleRequestHeaders = new string[4]
        {
      "Origin",
      "Accept",
      "Accept-Language",
      "Content-Language"
        };
        internal static readonly string[] SimpleResponseHeaders = new string[6]
        {
      "Cache-Control",
      "Content-Language",
      "Content-Type",
      "Expires",
      "Last-Modified",
      "Pragma"
        };
        internal static readonly string[] SimpleMethods = new string[3]
        {
      "GET",
      "HEAD",
      "POST"
        };
    }
}

享受!

答案 2 :(得分:3)

开箱即用的CorsService使用policy.Origins.Contains(origin)来评估请求。因此,它看起来并不像你需要的那样简单,因为List必须包含原点。您可以实现自己的ICorsService,继承开箱即用的CorsService已经提供的内容,并调整处理*.mydomain.com通配符的方法。

修改以下是我使用yo aspnet生成1.0.0-rc1-update2 Web Api项目所取得的成就。有用。在Startup.cs中注册您的服务(有关详细信息,请参阅CorsServiceCollectionExtensions。)

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();

        services.TryAdd(
            ServiceDescriptor.Transient<ICorsService, MyCorsService>());

        services.TryAdd(
            ServiceDescriptor.Transient<ICorsPolicyProvider, DefaultCorsPolicyProvider>());
    }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(minLevel: LogLevel.Verbose);

        app.UseCors(corsPolictyBuilder =>
        {
            corsPolictyBuilder.WithOrigins("*.mydomain.com");
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync(
                $"Is Cors? {context.Request.Headers.ContainsKey(CorsConstants.Origin)}");
        });
    }
}

这是服务,等待您的实施。您可以从CorsService复制/粘贴或继承。

public class MyCorsService : CorsService, ICorsService
{
    private ILogger _logger;

    public MyCorsService(IOptions<CorsOptions> options, ILogger<MyCorsService> logger)
        : base(options)
    {
        _logger = logger;
        _logger.LogInformation("MyCorsService");
    }

    public override void ApplyResult(
        CorsResult result, HttpResponse response)
    {
        _logger.LogInformation("ApplyResult");
        base.ApplyResult(result, response);
    }

    public override void EvaluateRequest(
        HttpContext context, CorsPolicy policy, CorsResult result)
    {
        _logger.LogInformation("EvaluateRequest");
        base.EvaluateRequest(context, policy, result);
    }

    public override void EvaluatePreflightRequest(
        HttpContext context, CorsPolicy policy, CorsResult result)
    {
        _logger.LogInformation("EvaluatePreflightRequest");
        base.EvaluatePreflightRequest(context, policy, result);
    }
}

答案 3 :(得分:0)

好的,因为劳埃德·鲍威尔(Lloyd Powell)和其他人(Other)回答了这个问题,所以这不能回答这个问题。但是仅供参考,您最好不要将此代码添加到ConfigureServices方法中!尝试使用扩展方法将此代码移动到单独的文件中;)

答案 4 :(得分:0)

如果在子域的第一部分指定通配符,例如,

SetIsOriginAllowedToAllowWildcardSubdomains函数运行良好。 https:\\*.modules.features.releaseversion.companyname.com,但例如在子域的任何其他部分指定了通配符时,相同的功能将无法获得理想的结果。 https:\\environment.modules.*.releaseversion.companyname.comhttps:\\*.modules.*.releaseversion.companyname.comhttps:\\environment.*.*.releaseversion.companyname.com

以下代码的灵感来自@Shaun Luttin和@sjdirect代码片段

我们只是想扩展Microsoft.AspNetCore.Cors.Infrastructure.CorsService类的行为,以启用URL中任意位置指定的通配符的使用

下面的类执行CORS检查以允许通配符子域。将此类本地复制到所需的项目中。它是Microsoft.AspNetCore.Cors.Infrastructure.CorsService的扩展版本,可为子域启用通配符支持。

    using Microsoft.AspNetCore.Cors.Infrastructure;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Microsoft.Extensions.Primitives;
    using System;
    using System.Text.RegularExpressions;

namespace Microsoft.AspNetCore.Cors.Infrastructure
{
    public class CORSServiceWildCardSupport : CorsService, ICorsService
    {
        private readonly CorsOptions _options;
        private readonly ILogger _logger;
        public CORSServiceWildCardSupport(IOptions<CorsOptions> options, ILoggerFactory loggerFactory) : base(options, loggerFactory)
        {
            _options = options.Value;
            _logger = loggerFactory.CreateLogger<CorsService>();
        }

        public new virtual CorsResult EvaluatePolicy(HttpContext context, CorsPolicy policy)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (policy == null)
            {
                throw new ArgumentNullException("policy");
            }
            if (policy.AllowAnyOrigin && policy.SupportsCredentials)
            {
                throw new ArgumentException(Resource.InsecureConfiguration, "policy");
            }
            IHeaderDictionary headers = context.Request.Headers;
            StringValues origin = headers[CorsConstants.Origin];

            bool num = string.Equals(context.Request.Method, CorsConstants.PreflightHttpMethod, StringComparison.OrdinalIgnoreCase);
            bool flag = num && headers.ContainsKey(CorsConstants.AccessControlRequestMethod);

            CorsResult result = new CorsResult
            {
                IsPreflightRequest = flag,
                IsOriginAllowed = IsWildCardSubdomainMatch(origin, policy)
            };
            if (flag)
            {
                EvaluatePreflightRequest(context, policy, result);
            }
            else
            {
                EvaluateRequest(context, policy, result);
            }
            return result;
        }

        protected virtual IsWildCardSubdomainMatch(string origin, CorsPolicy policy)
        {
            var actualOrigin = new Uri(origin);
            foreach (var o in policy.Origins)
            {
                if (IsWildcardMatch(actualOrigin, o))
                {
                    return true;
                }
            }
            return false;
        }

        private bool IsWildcardMatch(Uri actualOrigin, string wildcardUri)
        {
            if (!wildcardUri.StartsWith(actualOrigin.Scheme))
            {
                return false;
            }
            var wildcardUriMinusScheme = wildcardUri.Replace(actualOrigin.Scheme + "://", "");
            var regexFirstStage = wildcardUriMinusScheme.Replace(".", "\\.");
            var regexAllowedHosts = "^" + regexFirstStage.Replace("*", ".*") + "$";
            var actualOriginMinusScheme = actualOrigin.OriginalString.Replace(actualOrigin.Scheme + "://", "");
            var isMatch = Regex.IsMatch(actualOriginMinusScheme, regexAllowedHosts);
            return isMatch;
        }
    }
}

根据上面的类函数,可以根据要求扩展IsWildCardSubdomainMatch或IsWildcardMatch,对于我们的要求,我们只需要执行字符串比较即可。

使用以下扩展类将CORSServiceWildCardSupport类注册到依赖项容器中。将课程本地复制到所需的项目中

using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
namespace Microsoft.Extensions.DependencyInjection
{
    public static class CORSServiceCollectionExtensions
    {
        public static IServiceCollection AddCORSWithWildCardSupport(this IServiceCollection services)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }
            services.AddOptions();
            services.TryAdd(ServiceDescriptor.Transient<ICorsService, CORSServiceWildCardSupport>());
            services.TryAdd(ServiceDescriptor.Transient<ICorsPolicyProvider, DefaultCorsPolicyProvider>());
            return services;
        }

        public static IServiceCollection AddCORSWithWildCardSupport(this IServiceCollection services, Action<CorsOptions> setupAction)
        {
            if (services == null)
            {
                throw new ArgumentNullException("services");
            }
            if (setupAction == null)
            {
                throw new ArgumentNullException("setupAction");
            }
            services.AddCORSWithWildCardSupport();
            services.Configure(setupAction);
            return services;
        }
    }
}

从Startup类注册CORS

public void ConfigureServices(IServiceCollection services)
        {
            try
            {
                string[] whitelist = {"https:\\environment.modules.*.releaseversion.companyname.com","https:\\*.modules.*.releaseversion.companyname.com","https:\\environment.*.*.releaseversion.companyname.com"};

                services.AddCORSWithWildCardSupport(o => o.AddPolicy(Resource.CorsPolicyName, builder =>
                {
                    builder.WithOrigins(whitelist)
                           .AllowAnyMethod()
                           .AllowAnyHeader()
                           .AllowCredentials();
                }));

                services.AddControllers();

                services.AddMvc(option => option.EnableEndpointRouting = false)
                    .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

                services.AddAuthentication("Windows");
            }
            catch(Exception ex)
            {
                Logger.Error($"Failed to start due to {ex.Message}.");
            }
        }

services.AddControllers方法还将ICORSService注册到依赖项容器中,因此始终在AddControllers之前使用AddCORS

享受:)