ASP.NET Core 内置了对 CORS 的支持,使用很简单,只需先在 Startup 的 ConfigureServices() 中添加 CORS 策略:

public void ConfigureServices(IServiceCollection services)
{services.AddCors(options => options.AddPolicy("AllowSameDomain",builder => builder.WithOrigins("http://www.cnblogs.com","https://q.cnblogs.com","https://zzk.cnblogs.com","https://i.cnblogs.com","https://news.cnblogs.com","https://job.cnblogs.com")));
}

然后在想启用 CORS 的控制器 Action 上应用这个策略:

[EnableCors("AllowSameDomain")]
public IActionResult Markdown()
{return View();
}

但是,当看到上面一堆网址时,当想到每增加一个二级域名都需要修改上面的代码时,一种不舒服的感觉油然而生,一种想偷懒的冲动涌上心头。

难道没有一劳永逸的方法吗?DNS解析中支持在域名中使用通配符(*.cnblogs.com),CA证书中也支持,如果这里的 CORS 策略也支持使用通配符,不就可以一劳永逸了吗?配置 CORS 策略的代码就可以简化为下面的样子:

public void ConfigureServices(IServiceCollection services)
{services.AddCors(options => options.AddPolicy("AllowSameDomain",builder => builder.WithOrigins("*.cnblogs.com")));
}

不仅一劳永逸,而且代码更加简洁漂亮。

可是负责 ASP.NET CORS 的开发者没这么贴心,只能自己动手了。

从 github 签出 ASP.NET CORS 的源代码,找到其中根据域名进行判断的实现代码:

public class CorsService : ICorsService
{public virtual void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result){var origin = context.Request.Headers[CorsConstants.Origin];if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin)){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[CorsConstants.Origin];if (StringValues.IsNullOrEmpty(origin) || !policy.AllowAnyOrigin && !policy.Origins.Contains(origin)){return;}//...}
}

(这里竟然有重复代码,又增添了一份不舒服的感觉,暂且不管)

原来是通过 !policy.Origins.Contains(origin) 判断的,只要修改这个地方的判断代码,就能实现一劳永逸的偷懒目的。但是,这部分代码不是随意可以修改的,要走代码贡献流程,而且不一定被接受,目前还是先想办法扩展它吧。

英明的 ASP.NET CORS 开发者早就考虑了这个地方的扩展性,将 EvaluateRequest() 与 EvaluatePreflightRequest 定义为虚拟方法,我们只需定义一个子类继承自 CorsService ,覆盖这两个方法即可。

接下来就是解决如何覆盖的问题。把父类中的实现代码复制过来修改不可取,以后 ASP.NET CORS 升级了,这部分代码改了,就会带来问题。我们需要想办法在不改变现有处理逻辑的前提下,影响处理结果。

我们继续看 !policy.Origins.Contains(origin) ,policy.Origins 的类型是 IList<string> ,它存储的就是我们在定义 CORS 策略时添加的网址,所以,如果我们想要影响这里的判断结果,唯有改变 policy.Origins 的值。

根据当前的情况,我们可以把问题简化为下面的代码:

public static void Main(string[] args)
{IList<string> origins = new List<string>() { "*.cnblogs.com" };            var origin = "http://www.cnblogs.com";//在origins中添加"http://www.cnblogs.com"Assert.True(origins.Contains(origin));
}

接下来只需做一件事——集中精力把上面域名出售平台注释变成代码。

。。。

我们将注释变成了下面的代码:

private void EvaluateOriginForWildcard(IList<string> origins, string origin)
{//只在没有匹配的origin的情况下进行操作if (!origins.Contains(origin)){//查询所有以星号开头的originvar wildcardDomains = origins.Where(o => o.StartsWith("*"));if (wildcardDomains.Any()){//遍历以星号开头的originforeach (var wildcardDomain in wildcardDomains){//如果以.cnblogs.com结尾if (origin.EndsWith(wildcardDomain.Substring(1))//或者以//cnblogs.com结尾,针对http://cnblogs.com|| origin.EndsWith("//" + wildcardDomain.Substring(2))){//将http://www.cnblogs.com添加至originsorigins.Add(origin);break;}}}}
}

然后基于上面的代码实现 CorsService 的子类 WildcardCorsService :

public class WildcardCorsService : CorsService
{public WildcardCorsService(IOptions<CorsOptions> options): base(options){}public override void EvaluateRequest(HttpContext context, CorsPolicy policy, CorsResult result){var origin = context.Request.Headers[CorsConstants.Origin];EvaluateOriginForWildcard(policy.Origins, origin);base.EvaluateRequest(context, policy, result);}public override void EvaluatePreflightRequest(HttpContext context, CorsPolicy policy, CorsResult result){var origin = context.Request.Headers[CorsConstants.Origin];EvaluateOriginForWildcard(policy.Origins, origin);base.EvaluatePreflightRequest(context, policy, result);}private void EvaluateOriginForWildcard(IList<string> origins, string origin){//...}
}

然后将其注入:

services.Add(ServiceDescriptor.Transient<ICorsService, WildcardCorsService>());

(注:这里要用 Add ,不要用 TryAdd ,因为在 service.AddMvc 中已经把 CorsService 注入了,用 Add 才能覆盖 CorsService 的注入。)

最终 ConfigureServices() 中的代码变成了这样:

public void ConfigureServices(IServiceCollection services)
{services.AddMvc();services.Add(ServiceDescriptor.Transient<ICorsService, WildcardCorsService>());services.Configure<CorsOptions>(options => options.AddPolicy("AllowSameDomain",builder => builder.WithOrigins("*.cnblogs.com")));
}

一劳永逸的目标就此达成,不舒服的感觉烟消云散。

一劳永逸:域名支持通配符,ASP.NET Core中配置CORS相关推荐

  1. ASP.NET Core中配置监听URLs的六种方式

    默认情况下,ASP. NET Core应用会监听一下2个Url: http://localhost:5000 https://localhost:5001 在本篇博文中,我将展示如何使用五种不同的方式 ...

  2. 如何在 ASP.Net Core 中使用 HTTP.sys WebServer ?

    ASP.Net Core 是一个开源的,跨平台的,轻量级模块化框架,可用它来构建高性能的Web程序,大家都知道 Kestrel 是 ASP.Net Core 内置的跨平台web服务器,但是它有一定的局 ...

  3. 在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持

    HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable ...

  4. 重学ASP.NET Core 中的标记帮助程序

    标记帮助程序是什么 标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素. 例如,内置的 ImageTagHelper 可以将版本号追加到图片名称.  每当图片发生变化时 ...

  5. 如何在 ASP.NET Core 中发送邮件

    前言 我们知道目前 .NET Core 还不支持 SMTP 协议,当我么在使用到发送邮件功能的时候,需要借助于一些第三方组件来达到目的,今天给大家介绍两款开源的邮件发送组件,它们分别是 MailKit ...

  6. 如何使用C#在ASP.NET Core中轻松实现QRCoder

    by Yogi 由瑜伽士 如何使用C#在ASP.NET Core中轻松实现QRCoder (How to easily implement QRCoder in ASP.NET Core using ...

  7. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  8. 在 ASP.NET Core 中集成 Skywalking APM

    前言 大家好,今天给大家介绍一下如何在 ASP.NET Core 项目中集成 Skywalking,Skywalking 是 Apache 基金会下面的一个开源 APM 项目,有些同学可能会 APM ...

  9. .ASP NET Core中缓存问题案例

    本篇博客中,我将描述一个关于会话状态(Session State)的问题, 这个问题我已经被询问了好几次了. 问题的场景 创建一个新的ASP.NET Core应用程序 一个用户在会话状态中设置了一个字 ...

最新文章

  1. Android ListView (多个adapter 说明)
  2. 提高IIS网站服务器的效率的八种方法 (转载)
  3. R语言生成组合图并保存实战:实际上只保存了最后一个图问题、ggsave生成组合图并保存(保存完整组合图)
  4. mysql 5.6 与5.7 区别_mysql5.6和5.7的区别
  5. The MIT License (MIT)
  6. 第二章 反向传播算法如何工作的?
  7. linux需要检测的系统资源不足,细说Linux 系统优化
  8. 中文版putty后门事件的曝光过程及我们所受到的报复
  9. python输入4个数字_输入4个整数,要求按从小到大的顺序输出python
  10. C语言作业练习1:输入一个数判断是否为素数
  11. On Robust Capon Beamforming and Diagonal Loading
  12. sai 绘图软件快捷键
  13. php简单文章,PHP简单实现“相关文章推荐”功能的方法
  14. PHP实现文件上传功能实例代码
  15. 原创如何看机械硬盘SMART信息
  16. windows下CUDA的卸载,怒推!!!亲测可以!!!
  17. 【笔试面试考点】PreparedStatement和Statement的区别与联系批量插入数据的优化
  18. Error Code: 1265. Data truncated for column
  19. linux php配置
  20. audio驱动之codec和codec_dai

热门文章

  1. 计算机语言中空下划线,2017-7-31 Shell脚本编程基础
  2. 交大网院计算机第五次作业答案,交大网院计算机第三次作业分析.docx
  3. python电子相册制作代码大全_20 行 Python 代码即可制作精美证件照
  4. 为什么Internet选择分组交换而不是电路交换_交换机和路由器的区别有哪些?
  5. linux 权限模式,Linux权限模式
  6. aspose java_Aspose.Cells for Java
  7. Bootstrap(自助法),Bagging,Boosting(提升)
  8. 用set和shopt设置bash选项
  9. printf()输出
  10. 第二节:垃圾回收期算法简介