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))
{
//查询所有以星号开头的origin
var wildcardDomains = origins.Where(o => o.StartsWith("*"));
if (wildcardDomains.Any())
{
//遍历以星号开头的origin
foreach (var wildcardDomain in wildcardDomains)
{
//如果以.cnblogs.com结尾
if (origin.EndsWith(wildcardDomain.Substring())
//或者以//cnblogs.com结尾,针对http://cnblogs.com
|| origin.EndsWith("//" + wildcardDomain.Substring()))
{
//将http://www.cnblogs.com添加至origins
origins.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 提供了内置支持,示例代码如下

services.AddCors(options => options.AddPolicy(
"CnblogsCors",
p => p.SetIsOriginAllowedToAllowWildcardSubdomains()
.WithOrigins("https://*.cnblogs.com", "http://*.cnblogs.com")
.AllowAnyMethod().AllowAnyHeader()));

一劳永逸:域名支持通配符,ASP.NET Core中配置CORS的更多相关文章

  1. 一劳永逸:域名支持通配符,ASP.NET Core中配置CORS更轻松

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

  2. 如何在ASP.NET Core中实现CORS跨域

    注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...

  3. Asp.Net Core中配置使用Kindeditor富文本编辑器实现图片上传和截图上传及文件管理和上传(开源代码.net core3.0)

    KindEditor使用JavaScript编写,可以无缝的于Java..NET.PHP.ASP等程序接合. KindEditor非常适合在CMS.商城.论坛.博客.Wiki.电子邮件等互联网应用上使 ...

  4. 在Asp.Net Core中配置使用MarkDown富文本编辑器实现图片上传和截图上传(开源代码.net core3.0)

    我们的富文本编辑器不能没有图片上传尤其是截图上传,下面我来教大家怎么实现MarkDown富文本编辑器截图上传和图片上传. 1.配置编辑器到html页 <div id="test-edi ...

  5. ASP.NET Core中配置监听URLs的五种方式

    原文: 5 ways to set the URLs for an ASP.NET Core app 作者: Andrew Lock 译者: Lamond Lu 默认情况下,ASP. NET Core ...

  6. 【aspnetcore】在asp.net core中配置使用AutoMapper

    网上使用AutoMapper的文章很多,就不多说了.这里主要记录一下怎么在项目中配置和使用. 首先是从NuGet获取AutoMapper. 在Startup.cs文件中注册AutoMapper服务 p ...

  7. ASP.NET Core中的数据保护

    在这篇文章中,我将介绍ASP.NET Core 数据保护系统:它是什么,为什么我们需要它,以及它如何工作. 为什么我们需要数据保护系统? 数据保护系统是ASP.NET Core使用的一组加密api.加 ...

  8. 在Asp.Net或.Net Core中配置使用MarkDown富文本编辑器有开源模板代码(代码是.net core3.0版本)

    研究如何使用Markdown你们可能要花好几天才能搞定,但是看我的文章或者下载了源码,你搞定一般在10分钟之内.我先给各位介绍下它: Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯 ...

  9. ASP.NET Core 中jwt授权认证的流程原理

    目录 1,快速实现授权验证 1.1 添加 JWT 服务配置 1.2 颁发 Token 1.3 添加 API访问 2,探究授权认证中间件 2.1 实现 Token 解析 2.2 实现校验认证 1,快速实 ...

随机推荐

  1. 基于Ubuntu搭建Seafile专属网盘

    系统要求: Ubuntu 16.04.1 LTS 64 位操作系统 安装 Seafile 服务器 安装依赖环境 在 Debian/Ubuntu 系统下,可以使用以下命令安装 MySQL: sudo a ...

  2. Apache Spark 2.3.0 重要特性介绍

    文章标题 Introducing Apache Spark 2.3 Apache Spark 2.3 介绍 Now Available on Databricks Runtime 4.0 现在可以在D ...

  3. 格雷码(Gray code)仿真

    作者:桂. 时间:2018-05-12  16:25:02 链接:http://www.cnblogs.com/xingshansi/p/9029081.html 前言 FIFO中的计数用的是格雷码, ...

  4. [k8s]k8s配置nfs做后端存储&配置多nginx共享存储&&statefulset配置

    所有节点安装nfs yum install nfs-utils rpcbind -y mkdir -p /ifs/kubernetes echo "/ifs/kubernetes 192.1 ...

  5. 物联网架构成长之路(22)-Docker练习之Etcd服务搭建

    0. 前言 时隔多日,前段时间忙完一个可有可无的项目后,又进入摸鱼时间,没有办法,非互联网公司,就是闲得蛋疼.又开始了自学之路.以前入门过Docker,然后又很久没有看了,最近重新看了一下,推荐一下这 ...

  6. 3. Tensorflow生成TFRecord

    1. Tensorflow高效流水线Pipeline 2. Tensorflow的数据处理中的Dataset和Iterator 3. Tensorflow生成TFRecord 4. Tensorflo ...

  7. Public key for ambari-server-2.4.2.0-136.x86_64.rpm is not installed 安装ambari报错总结

    提示;# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release 就是导入这个安装包的key 可以使用http的协议 比如我用的就是 rpm ...

  8. Linux下MySQL5.7.18二进制包安装(无默认配置文件my_default.cnf)

    最新在学习MySQL,纯新手,对Linux了解的也不多,因为是下载的最新版的MySQL(MySQL5.7.18)二进制包,CentOS7.2下测试安装,方便以后折腾.大概步骤如下,安装删除反复折腾了几 ...

  9. Ubuntu上查内存情况

    free -h

  10. vue项目在安卓低版本机显示空白原因

    vue项目在安卓低版本机显示空白原因: 可能的原因一: 查看安卓debug,报错,可能有箭头函数语法错误,或者其他语法问题,那可能是ES6语法问题. 这时候需要安装babel-pollyfill. 网 ...