【问题标题】:Configure cors to allow all subdomains using ASP.NET Core (Asp.net 5, MVC6, VNext)配置 cors 以允许使用 ASP.NET Core(Asp.net 5、MVC6、VNext)的所有子域
【发布时间】:2016-08-21 00:47:13
【问题描述】:

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

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

这里是 startup.cs sn-p...

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。如何在新堆栈中实现这一点?

【问题讨论】:

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


    【解决方案1】:

    这已在 2.0.0 版中实现。在您的 ConfigureServices 中使用以下内容:

    options.AddPolicy("MyCorsPolicy",
       builder => builder
          .SetIsOriginAllowedToAllowWildcardSubdomains()
          .WithOrigins("https://*.mydomain.com")
          .AllowAnyMethod()
          .AllowCredentials()
          .AllowAnyHeader()
          .Build()
       );
    

    另外,不要忘记在您的 Configure 电话中也致电 UseCors:

    app.UseCors("MyCorsPolicy");
    

    【讨论】:

    • 这对我有用,谢谢!另请参阅github.com/dotnet/AspNetCore.Docs/issues/9595 的结尾 - 答案相同
    • 这个答案是正确的。附加说明:如果您需要顶级域和子域,则需要同时添加 -> 例如.WithOrigins(new string[] { "https://*.example.com", "https://example.com" })
    • 接受了这个答案(几年后),而不是我下面的原始解决方法。显然这个帖子提交的时候是不存在的
    • @sjdirect 你的回答在当时是完美的解决方法!
    • 我已经尝试过使用 SetIsOriginAllowedToAllowWildcardSubdomains,它适用于类似的域,例如https://*.examples.functionality.companyname.com 但不适用于例如https://demo.*.functionality.companyname.com 在这种情况下,@sjdirect 提供的示例可以提供帮助。
    【解决方案2】:

    submitted a pull request 向 ASP.NET 团队发送了此更改,因此希望它能够进入 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 类的副本和编辑,以允许它处理通配符子域。如果找到通配符 '*',它将检查根域是否匹配允许的来源和实际来源。它不支持部分通配符匹配。

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

    享受吧!

    【讨论】:

    • 不应该将其注册为单例,而不是注册一个将为每个请求创建一个新实例的瞬态吗?
    • 在哪里添加?
    • 这很漂亮
    • 您的请求似乎已添加到 v2.0 中的CorsService。不仅CorsPolicyBuilder 现在有SetIsOriginAllowedToAllowWildcardSubdomains,而且还有SetIsOriginAllowed 需要一个lambda。
    【解决方案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);
        }
    }
    

    【讨论】:

    • 我希望有些事情不是那么亲力亲为。如果我采用上述方法,注入/使用该实现而不是当前实现的最佳方法是什么?仍在尝试围绕 Asp.net Core 提供的所有可能的 DI 方法。谢谢!
    • @sjdirect 你愿意使用RC2吗?
    • Shaun,此时我不会对升级感到兴奋,但我很想听听 RC2 为这个问题带来了什么缓解。
    • Shaun,我目前卡在 RC1 上,必须在我准备好升级到 RC2 之前完成这项改进。我编写了一个解决方案并提交了pull request to the asp.net team here。现在我想弄清楚如何插入我修改后的核心服务,而不是默认使用的 CorsService。
    • @sjdirect 我已经添加了如何插入您修改后的核心服务。
    【解决方案4】:

    当在子域的第一部分指定通配符时,SetIsOriginAllowedToAllowWildcardSubdomains 函数运行良好,例如https:\\*.modules.features.releaseversion.companyname.com 但是当在子域的任何其他部分指定通配符时,相同的函数不会给出所需的结果,例如https:\\environment.modules.*.releaseversion.companyname.comhttps:\\*.modules.*.releaseversion.companyname.comhttps:\\environment.*.*.releaseversion.companyname.com

    以下代码的灵感来自 @Shaun Luttin 和 @sjdirect 代码 sn-p

    我们只是想扩展 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

    享受:)

    【讨论】:

    • 互联网使用/而不是\(应该是https://www.example.com而不是https:\\www.example.com)。
    猜你喜欢
    • 2016-09-05
    • 2020-06-21
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 2019-08-19
    • 2015-07-27
    • 2015-01-24
    相关资源
    最近更新 更多