使用 Ocelot 匹配路由的方法匹配路由
使用 Ocelot 匹配路由的方法匹配路由
Intro
之前我们在 Ocelot 网关的基础上自定义了一个认证授权的 Ocelot 中间件,根据请求的路径和 Method 进行匹配,找到对应的权限配置,并判断是否可以拥有访问资源的角色,如果没有则返回 401/403,如果有权限则转发到下游服务。
原来的匹配方式是首先根据请求路径和方法完全匹配,如果匹配不到则尝试使用正则匹配。
我们这次要做的就是将原来的正则匹配替换成 Ocelot 內部的路由匹配方式,这样我们在配置的时候就不再需要配置两套了,一边写 Ocelot 路由的配置,一边写权限的配置,这样能减少不少工作量
深入 Ocelot 路由匹配
我们想使用 Ocelot 的路由匹配,首先应该了解 Ocelot 的执行过程,然后找到对应的路由匹配的地方,看路由匹配使用到了哪一个服务,用这个服务在我们自己的业务逻辑里匹配即可。
先来看一下 Ocelot 的服务注册,Ocelot 的服务注册

可以看到主要的服务注册代码应该在 OcelotBuilder 中,查看 OcelotBuilder https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DependencyInjection/OcelotBuilder.cs

可以看到,Ocelot 的服务注册都在这里, Ocelot 内部好多都是基于接口的,所以需要找对应的实现的话可以看它的服务注册是注册的哪一个服务即可。
简单分析一下,Ocelot 的路由匹配过程一定在寻找下游地址的时候,根据上游的请求信息(直接请求网关的请求)匹配,所以我们首先找到 DownstreamRouteFinderMiddleware https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs

由上面的代码,我们可以看到,下游路由地址是通过 IDownstreamRouteFinder 来找下游路由的,转到对应的实现代码: https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs

这里我们可以看到是通过 IUrlPathToUrlTemplateMatcher 来进行路由匹配的,所以我们需要用到这个服务,然后看这个 Match 方法的参数,前两个参数比较明确,第一个参数是上游请求的地址,第二个参数是请求的 queryString,第三个参数则是 Ocelot 内部构建出来的路由模板信息 UpstreamPathTemplate,然后我们就需要知道怎么构建一个 UpstreamPathTemplate 对象,继续探索
直接看 UpstreamPathTemplate,表示一脸懵逼,不知道怎么构建, 全局搜素了一下,发现有一个 IUpstreamTemplatePatternCreator 里面定义了一个 Create 的方法

这个方法看上去简单了好多,查看 IReRoute 的定义 https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/Configuration/File/IReRoute.cs

我们只需要根据路径模板构建一个 IReRoute 对象即可,Ocelot 中有一个实现了 IReRoute 的类 FileReRoute,但是感觉有些复杂,就没有用,自定义了一个类型实现了 IReRoute
自此,我们就已经找到了要使用 Ocelot 路由匹配所需要的服务了:
IUrlPathToUrlTemplateMatcherIUpstreamTemplatePatternCreator
使用 Ocelot 路由匹配
上面提到了我们没有使用 FileReRoute 对象,所以我们就需要自定义一个 IReRoute 对象:
private class FakeReRoute : IReRoute
{
public string UpstreamPathTemplate { get; set; }
public bool ReRouteIsCaseSensitive { get; set; }
public int Priority { get; set; }
}
使用 Ocelot 路由匹配示例:
public class UrlBasedAuthenticationMiddleware : Ocelot.Middleware.OcelotMiddleware
{
private readonly GatewayOptions _gatewayOptions;
private readonly IMemoryCache _memoryCache;
private readonly OcelotRequestDelegate _next;
private readonly IUrlPathToUrlTemplateMatcher _urlTemplateMatcher;
private readonly IUpstreamTemplatePatternCreator _templatePatternCreator;
public UrlBasedAuthenticationMiddleware(OcelotRequestDelegate next, IOptions<GatewayOptions> options, IMemoryCache memoryCache, IOcelotLoggerFactory loggerFactory,
IUrlPathToUrlTemplateMatcher urlTemplateMatcher,
IUpstreamTemplatePatternCreator templatePatternCreator)
: base(loggerFactory.CreateLogger<UrlBasedAuthenticationMiddleware>())
{
_next = next;
_gatewayOptions = options.Value;
_memoryCache = memoryCache;
_urlTemplateMatcher = urlTemplateMatcher;
_templatePatternCreator = templatePatternCreator;
}
public async Task Invoke(DownstreamContext context)
{
var permissions = await _memoryCache.GetOrCreateAsync(_gatewayOptions.ApiPermissionsCacheKey, async entry =>
{
using (var conn = new SqlConnection(_gatewayOptions.PermissionsConnectionString))
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
return (await conn.QueryAsync<ApiPermission>(@"")).Select(_ => _.GetViewModel()).ToArray();
}
});
var request = context.HttpContext.Request;
var permission = permissions.FirstOrDefault(p =>
request.Path.Value.Equals(p.PathPattern, StringComparison.OrdinalIgnoreCase) &&
p.Method == request.Method.ToUpper());
if (null == permission)
{
permission = permissions.FirstOrDefault(p =>
p.Method == request.Method.ToUpper() &&
_urlTemplateMatcher.Match(request.Path.Value, request.QueryString.Value,
_templatePatternCreator.Create(new FakeReRoute()
{
UpstreamPathTemplate = p.PathPattern
})).Data.Match
);
}
// ...
await _next.Invoke(context);
}
private class FakeReRoute : IReRoute
{
public string UpstreamPathTemplate { get; set; }
public bool ReRouteIsCaseSensitive { get; set; }
public int Priority { get; set; }
}
}
More
这样,apiPermission 的 Path 配置基本可以使用和 Ocelot 配置一样的路由,可以更方便的配置,避免 996 咯
Reference
- https://github.com/ThreeMammals/Ocelot
- https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DependencyInjection/OcelotBuilder.cs#L95
- https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DownstreamRouteFinder/UrlMatcher/IUrlPathToUrlTemplateMatcher.cs
使用 Ocelot 匹配路由的方法匹配路由的更多相关文章
- js 实现前端路由的方法
js 实现前端路由的方法 前端路由原理 History API https://developer.mozilla.org/en-US/docs/Web/API/History_API https:/ ...
- python中RabbitMQ的使用(路由键模糊匹配)
路由键模糊匹配 使用正则表达式进行匹配.其中“#”表示所有.全部的意思:“*”只匹配到一个词. 匹配规则: 路由键:routings = [ 'happy.work', 'happy.life' , ...
- xp多网卡静态路由设置方法
xp多网卡静态路由设置方法 一.多个IP都在同一网段或VALN.这类情况没什么好说的,在各块网卡的本地连接属性里设置好IP地址.子网掩码和默认网关即可. 二.多个IP属于不同网段或VLAN.这时如果按 ...
- MVC前后台获取Action、Controller、ID名方法 以及 路由规则
前后台获取Action.Controller.ID名方法 前台页面:ViewContext.RouteData.Values["Action"].ToString();//获取Ac ...
- linux下(Ubuntu、centos)添加永久静态路由的方法
项目中经常遇到多网卡的服务器,但是一个服务器的默认网关只有一个,当需要在多个网络中访问的时候(特别是在公安.交警等政府项目中),就需要添加静态路由了. 添加静态路由的方法有很多种,下面介绍2种比较常见 ...
- JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分)
JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分) 1.匹配属性的开头 $("[attributeName^='value']"); 2.匹配属性的结尾 ...
- 1.3 正则表达式和python语言-1.3.4使用 match()方法匹配字符串
1.3.4使用 match()方法匹配字符串(第一次写博客,格式,述语有不当之处还请见谅)2018-05-08 Python 代码是以Jupyter Notebook编写的,主要写的是python3的 ...
- CentOS 6.4 添加永久静态路由所有方法汇总(原创)
转摘,原文章地址:http://blog.sina.com.cn/s/blog_828e50020101ern5.html 查看路由的命令route -n CentOS添加永久静态路由 在使用双网卡, ...
- xpath的数据和节点类型以及XPath中节点匹配的基本方法
XPath数据类型 XPath可分为四种数据类型: 节点集(node-set) 节点集是通过路径匹配返回的符合条件的一组节点的集合.其它类型的数据不能转换为节点集. 布尔值(boolean) ...
随机推荐
- 初识web API接口及Restful接口规范
一.web API接口 什么是web API接口?: 明确了请求方式,提供对应后台所需参数,请求url链接可以得到后台的响应数据 url : 返回数据的url https://api.map.baid ...
- 使用 layUI做一些简单的表单验证
使用 layUI做一些简单的表单验证 <form method="post" class="layui-form" > <input name ...
- javascript 使用 setInterval 实现倒计时
javascript 使用 setInterval 实现倒计时 var timer = setInterval(function () { console.log(valid_time); if (v ...
- 管道 |、|&、tee
用“|”或“|&”隔开两个命令之间形成一个管道,左边命令的标准输出(|)或者标准错误输出(|&)信息流入到右边命令的标准输入,即左边命令的标准输出作为右边命令的标准输入.如: make ...
- ACE框架 基于共享内存的分配器 (算法设计)
继承上一篇<ACE框架 基于共享内存的分配器设计>,本篇分析算法部分的设计. ACE_Malloc_T模板定义了这样一个分配器组件 分配器组件聚合了三个功能组件:同步组件ACE_LOCK, ...
- 🔥《手把手教你》系列基础篇之4-python+ selenium自动化测试-xpath使用(详细教程)
1. 简介 俗话说:磨刀不误砍柴工,因此在我们要开始写自动化脚本之前,我们先来学习和了解几个基本概念,在完全掌握了这几个概念之后,有助于我们快速上手,如何去编写自动化测试脚本. 元素,在这个教程系列, ...
- springboot+swagger接口文档企业实践(下)
目录 1.引言 2. swagger接口过滤 2.1 按包过滤(package) 2.2 按类注解过滤 2.3 按方法注解过滤 2.4 按分组过滤 2.4.1 定义注解ApiVersion 2.4.2 ...
- 【CPLUSOJ】【动态规划】最短回文串
题目链接 [问题描述] 如果一个字符串正过来读和倒过来读是一样的,那么这个字符串就被称作回文串.例如abcdcba,abcddbca就是回文串,而abcdabcd不是. 你要解决的问题是:对于任意一个 ...
- Erlang/Elixir精选-第1期
第1期(20191202) 文章 A short guide to the structure and internals of the Erlang distributed messaging fa ...
- cbv请求分析
CBV源码分析 DRF中中所有视图都是基于CBV形式完成, 所以分析其cbv源码, 了解drf的基本请求流程就比较有必要了. urls.py """下面是一个通用的url ...