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 中写出更干净的 Controller

    你可以遵循一些最佳实践来写出更干净的 Controller,一般我们称这种方法写出来的 Controller 为瘦Controller,瘦 Controller 的好处在于拥有更少的代码,更加单一的职 ...

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

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

  9. asp.net core 中配合响应 html5 的音视频播放流,以及文件下载

    一.asp.net core 中配合响应 html5 的音视频播放流,以及文件下载 问题描述: 目前测试了在 Windows(谷歌浏览器).Android(系统浏览器.QQ.微信).iOS 三个系统不 ...

随机推荐

  1. Action向视图传值的6种方式

    在使用ASP.NET MVC进行项目开发时,经常会碰到从Action向视图传值的问题,今天我就把我所知道的方式总结了一下,分成了以下六种: 1.使用ViewData进行传值 在Action中,有如下代 ...

  2. 获取youku视频下载链接(wireshark抓包分析)

    随便说两句 前两天写了一个python脚本,试图以分析网页源码的方式得到优酷视频的下载地址,结果只得到视频的纯播放地址,下载纯播放地址得到的文件也无法正常播放视频. 这里共享一下播放地址得到的方法(想 ...

  3. MVVM页面跳转 技巧性标记

    刚学MVVM 百度了很多概念性的东西 也参考了网上的例子 基本有了了解 但是我发现 我做了一个登录页面以后 我跳转咋办呢? VM里面咋做跳转? 问了一下其他的群友得到了一些启发.感谢“上海*松” 我仅 ...

  4. jsp include flush true

    设置flush为true,就是说,如果你的缓冲区的内容很多了,就将数据读出,以免数据泄漏,造成错误服务器端页面缓冲,大致的意思是,在将生成的HTML代码送到客户端前,先在服务器端内存中保留,因为解释J ...

  5. webpack初试

    前言: 知道这完儿,没用过.关于webpack有很多介绍了,就不多说了.放几个链接,方便新手理解.这是给纯没用过的人了解的.这里只是简单介绍一下webpack的基本用法.大多内容都是来自webpack ...

  6. 更改pip安装源的镜像解决安装总是timeout的情况

    由于国外的pip源总是由于各种原因不能被访问或者网速过慢,而造成的timeout错误 解决方法是修改pip的配置文件(如果没有配置文件在相应的地方新建,配置文件的路径和名字参考这里),设置安装包时候访 ...

  7. MIT 6.828 JOS学习笔记17. Lab 3.1 Part A User Environments

    Introduction 在这个实验中,我们将实现操作系统的一些基本功能,来实现用户环境下的进程的正常运行.你将会加强JOS内核的功能,为它增添一些重要的数据结构,用来记录用户进程环境的一些信息:创建 ...

  8. PowerDesigner修改生成mysql视图

    今天遇到了个问题,就是有PowerDesigner的设计图,能生成oracle的视图,不能生成mysql,在网上找到了解决方案, 非常感谢各位网友的分享,这个不是抄袭,主要是为了让更多的人知道这种解决 ...

  9. 安卓四核PDA手持PDA智能POS机 打印二维码 分享

    很多项目都会用到 类似的要求  移动手持终端 通过程序 可以生成条码或二维码 打印出小票或标签纸 下面直接上代码 希望对大家有点用处 private void print(){ csys.setTex ...

  10. LeetCode 412. Fizz Buzz

    Problem: Write a program that outputs the string representation of numbers from 1 to n. But for mult ...