[2core]跨域资源共享CORS

迁移问题

在ASP.NET 4.x时期,解决CORS问题是非常容易的,仅需在配置文件web.config里增加相应的配置节点即可,无法在程序中进行编码。在ASP.NET Core中,一切都是DI+配置Options化,确实有些不太习惯,也没有时间研究CORS配置化实现方法。所以只能把CORS配置项保存到appsettings.json文件里,然后在代码中编码实现CORS功能,因此,本文重点记录实现过程。

 

解决方案

1.ASP.NET 4.x时期web.config文件配置CORS

<system.webServer>
        <httpProtocol>
            <customHeaders>
                <!--多个对象用英文逗号分隔-->
                <add name="Access-Control-Allow-Origin" value="*" />
                <!--若为true,Origin节点不能为*-->
                <add name="Access-Control-Allow-Credentials" value="false" />
                <!--多个对象用英文逗号分隔-->
                <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,HEAD,OPTIONS" />
                <!--多个对象用英文逗号分隔-->
                <add name="Access-Control-Allow-Headers" value="X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType" />
                <!--前端可以通过getResponseHeader读取值-->
                <add name="Access-Control-Expose-Headers" value="Set-Token" />
                <!--用来指定本次预检请求的有效期(20天),单位为秒,设置后有效期内不在发预检查请求-->
                <add name="Access-Control-Max-Age" value="2592000" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>

2.ASP.NET Core的玩法
1)在appsettings.json文件里配置好CORS项

{
  //配置CORS策略
  "CorsPolicy": {
    //多个对象用英文逗号分隔
    "AllowOrigins": "*",
    //若为true,Origin节点不能为*
    "AllowCredentials": "false",
    //多个对象用英文逗号分隔
    "AllowMethods": "GET,PUT,POST,DELETE,HEAD,OPTIONS",
    //多个对象用英文逗号分隔
    "AllowHeaders": "X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType",
    //前端可以通过getResponseHeader读取值
    "ExposeHeaders": "Set-Token",
   //用来指定本次预检请求的有效期(20天),单位为秒,设置后有效期内不在发预检查请求
"MaxAge": 8640000
  }
}

2)定义CORS策略对应的Options类CorsPolicyOptions

public class CorsPolicyOptions
    {
        public string AllowOrigins { get; set; } = "*";
        public bool AllowCredentials { get; set; } = false;
        public string AllowMethods { get; set; } = "GET,PUT,POST,DELETE,HEAD,OPTIONS";
        public string AllowHeaders { get; set; } = "X-Requested-With,origin,content-length,content-type,accept,Authorization";
        public string ExposeHeaders { get; set; } = "Set-Token";
        public int MaxAge { get; set; } = 8640000;
    }

3)定义appsettings.json文件对应的AppSettings类文件,在AppSettings类的私有类里实现CORS策略的读取

public class AppSetting
    {
        private static object _objLocker = new object();
        private static AppSetting _instance;
        private AppSetting() { }
        public static AppSetting Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_objLocker)
                    {
                        if (_instance == null)
                        {
                            _instance = new AppSetting();
                            AppSettingConfig.Load(_instance);
                        }
                    }
                }
                return _instance;
            }
        }
        private class AppSettingConfig
        {
            private static AppSetting _appSetting;
            public static void Load(AppSetting appSetting)
            {
                _appSetting = appSetting;

                Compute();
                ChangeToken.OnChange(() => ConfigObjectManager.Instance.AppSetting.GetReloadToken(), () => { Change(); });
            }
            private static void Compute()
            {
                _appSetting.CorsPolicy = ConfigObjectManager.Instance.AppSetting.GetSection(ConstFiles.AppSettings_CorsPolicy).Get<CorsPolicyOptions>();
            }
            private static void Change()
            {

            }
        }

        #region Object Propertries
        public CorsPolicyOptions CorsPolicy { get; private set; }
        #endregion
    }

4)配置CORS

public static void Config(IServiceCollection services)
        {
            if (AppSetting.Instance.CorsPolicy != null)
            {
                services.AddCors(options =>
                {
                    options.AddDefaultPolicy(bd =>
                    {
                        if ("*" == AppSetting.Instance.CorsPolicy.AllowOrigins)
                        {
                            bd.SetIsOriginAllowed(_ => true);
                        }
                        else
                        {
                            var _tmpArray = AppSetting.Instance.CorsPolicy.AllowOrigins.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                            bd.WithOrigins(_tmpArray);
                        }

                        if (AppSetting.Instance.CorsPolicy.AllowCredentials)
                        {
                            bd.AllowCredentials();
                        }
                        else
                        {
                            bd.DisallowCredentials();
                        }

                        var _tmpMethods = AppSetting.Instance.CorsPolicy.AllowMethods.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.AllowMethods : "GET,PUT,POST,DELETE,HEAD,OPTIONS";
                        bd.WithMethods(_tmpMethods);

                        var _tmpHeaders = AppSetting.Instance.CorsPolicy.AllowHeaders.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.AllowHeaders : "X-Requested-With,origin,content-length,content-type,accept,Authorization,ApplicationType,LanguageType";
                        bd.WithHeaders(_tmpHeaders);

                        var _tmpExposedHeaders = AppSetting.Instance.CorsPolicy.ExposeHeaders.IsNotNullEmptyWhiteSpace() ? AppSetting.Instance.CorsPolicy.ExposeHeaders : "";
                        bd.WithExposedHeaders(_tmpExposedHeaders);

                        var _tmpMaxAge = AppSetting.Instance.CorsPolicy.MaxAge > 1440 ? AppSetting.Instance.CorsPolicy.MaxAge : 8640000;
                        bd.SetPreflightMaxAge(TimeSpan.FromSeconds(_tmpMaxAge));
                    });
                });
            }
        }

5)启用CORS

public static void Start(IApplicationBuilder app)
        {
            if (AppSetting.Instance.CorsPolicy != null)
            {
                app.UseCors();
            }
        }

 

总结

CORS在ASP.NET Core中实现还是比较简单的,只是习惯了不把可以配置化实现的代码写死在代码中,所以才有了上述编码逻辑。在上述代码中,我比较满意巨硬提供把配置文件中的对象转换为类对象这个操作的,想起在ASP.NET 4.x项目中都是手动实现,特别说明:咋ASP.NET 4.x项目中使用的配置文件格式ini。

测试源码:https://gitee.com/kinbor/jks.core.test.corsandconfig

posted @ 2022-10-09 14:45  oO归客Oo  阅读(46)  评论(0编辑  收藏  举报