Configure cors to allow all subdomains using ASP.NET Core (Asp.net 5, MVC6, VNext)

后端 未结 4 1662
甜味超标
甜味超标 2020-12-10 00:51

I have cors setup correctly in an ASP.NET Core web app. Im using the following package...

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

an

4条回答
  •  南笙
    南笙 (楼主)
    2020-12-10 01:34

    SetIsOriginAllowedToAllowWildcardSubdomains function works well when the wildcard character is specified at the first part of the subdomains for e.g. https:\\*.modules.features.releaseversion.companyname.com but the same function doesn't give the desired result when the wildcard character is specified at any other part of the subdomain for e.g. https:\\environment.modules.*.releaseversion.companyname.com or https:\\*.modules.*.releaseversion.companyname.com or https:\\environment.*.*.releaseversion.companyname.com

    Below code is inspired from the @Shaun Luttin and @sjdirect code snippet

    We just wanted to extend the behaviour of the Microsoft.AspNetCore.Cors.Infrastructure.CorsService class to enable usage of wildcard character specified anywhere in the URL

    Below class performs the CORS check to allow wild card subdomains. Copy this class locally into the desired project. It's an extended version of the Microsoft.AspNetCore.Cors.Infrastructure.CorsService to enable wild card support for subdomains.

        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 options, ILoggerFactory loggerFactory) : base(options, loggerFactory)
            {
                _options = options.Value;
                _logger = loggerFactory.CreateLogger();
            }
    
            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;
            }
        }
    }
    

    From the above class function IsWildCardSubdomainMatch or IsWildcardMatch can be extended based on the requirement, for our requirement we just needed to perform string comparison.

    Register the CORSServiceWildCardSupport class into the dependency container using the below extension class. Copy the class locally into the desired project

    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());
                services.TryAdd(ServiceDescriptor.Transient());
                return services;
            }
    
            public static IServiceCollection AddCORSWithWildCardSupport(this IServiceCollection services, Action setupAction)
            {
                if (services == null)
                {
                    throw new ArgumentNullException("services");
                }
                if (setupAction == null)
                {
                    throw new ArgumentNullException("setupAction");
                }
                services.AddCORSWithWildCardSupport();
                services.Configure(setupAction);
                return services;
            }
        }
    }
    

    Register the CORS from the Startup class

    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 method also registers ICORSService into the dependency container hence always use AddCORS prior to AddControllers

    Enjoy :)

提交回复
热议问题