使用 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 路由匹配所需要的服务了:

  • IUrlPathToUrlTemplateMatcher
  • IUpstreamTemplatePatternCreator

使用 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

使用 Ocelot 匹配路由的方法匹配路由的更多相关文章

  1. js 实现前端路由的方法

    js 实现前端路由的方法 前端路由原理 History API https://developer.mozilla.org/en-US/docs/Web/API/History_API https:/ ...

  2. python中RabbitMQ的使用(路由键模糊匹配)

    路由键模糊匹配 使用正则表达式进行匹配.其中“#”表示所有.全部的意思:“*”只匹配到一个词. 匹配规则: 路由键:routings = [ 'happy.work',  'happy.life' , ...

  3. xp多网卡静态路由设置方法

    xp多网卡静态路由设置方法 一.多个IP都在同一网段或VALN.这类情况没什么好说的,在各块网卡的本地连接属性里设置好IP地址.子网掩码和默认网关即可. 二.多个IP属于不同网段或VLAN.这时如果按 ...

  4. MVC前后台获取Action、Controller、ID名方法 以及 路由规则

    前后台获取Action.Controller.ID名方法 前台页面:ViewContext.RouteData.Values["Action"].ToString();//获取Ac ...

  5. linux下(Ubuntu、centos)添加永久静态路由的方法

    项目中经常遇到多网卡的服务器,但是一个服务器的默认网关只有一个,当需要在多个网络中访问的时候(特别是在公安.交警等政府项目中),就需要添加静态路由了. 添加静态路由的方法有很多种,下面介绍2种比较常见 ...

  6. JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分)

    JQUERY选择和操作DOM元素(利用正则表达式的方法匹配字符串中的一部分) 1.匹配属性的开头 $("[attributeName^='value']"); 2.匹配属性的结尾 ...

  7. 1.3 正则表达式和python语言-1.3.4使用 match()方法匹配字符串

    1.3.4使用 match()方法匹配字符串(第一次写博客,格式,述语有不当之处还请见谅)2018-05-08 Python 代码是以Jupyter Notebook编写的,主要写的是python3的 ...

  8. CentOS 6.4 添加永久静态路由所有方法汇总(原创)

    转摘,原文章地址:http://blog.sina.com.cn/s/blog_828e50020101ern5.html 查看路由的命令route -n CentOS添加永久静态路由 在使用双网卡, ...

  9. xpath的数据和节点类型以及XPath中节点匹配的基本方法

    XPath数据类型  XPath可分为四种数据类型:  节点集(node-set)  节点集是通过路径匹配返回的符合条件的一组节点的集合.其它类型的数据不能转换为节点集.  布尔值(boolean)  ...

随机推荐

  1. 如何给HTML标签中的文本设置修饰线

    text-decoration属性介绍 text-decoration属性是用来设置文本修饰线呢,text-decoration属性一共有4个值. text-decoration属性值说明表 值 作用 ...

  2. C++中对C的扩展学习新增语法——动态内存管理

    1.C语言动态内存管理的缺点: 1.malloc对象的大小需要自己计算. 2.需要手动转换指针类型. 3.C++的对象不适合使用malloc和free. 2.C++中new/delete基本使用: 3 ...

  3. PHP 7.4 新语法:箭头函数

    短闭包,也叫做箭头函数,是一种用 php 编写的短函数.当向函数中传递闭包时,这个功能是非常有用的,比如使用 array_map 或是 array_filter 函数时. 译者注:PHP7.4 计划于 ...

  4. (C#)WPF:关于INotifyPropertyChanged接口的介绍

    注意:INotifyPropertyChanged接口位于System.CompenentModel名称空间中,想使用INotifyPropertyChanged接口时,头文件需添加“using Sy ...

  5. (二十六)golang--切片

    基本介绍: 切片是数组的引用: 切片的使用和数组类似: 切片的长度是可以变化的: 切片的定义 var a []int,注意和数组定义的区别: 切片不仅可以使用len函数,还有cap函数来计算切片的容量 ...

  6. 微擎签名出错 invalid signature

    微擎签名出错 错误信息: config:fail,Error: 系统错误,错误码:63002,invalid signature 修改方法: PHP 端 $account_api = WeAccoun ...

  7. 领扣(LeetCode)两数之和II - 输入有序数组 个人题解

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...

  8. SQL Server设计三范式

    第一范式(1NF) (必须有主键,列不可分) 数据库表中的任何字段都是单一属性的,不可再分 create table aa(id int,NameAge varchar(100)) insert aa ...

  9. AE ArcEngine10.4+vs2012安装配置

    准备内容 安装环境:win10*64位专业版,ArcGIS_Desktop_1041_151727,C#语言环境,visual studio2012 安装文件:ArcGIS_Engine_1041_1 ...

  10. RNN-LSTM讲解-基于tensorflow实现

    cnn卷积神经网络在前面已经有所了解了,目前博主也使用它进行了一个图像分类问题,基于kaggle里面的food-101进行的图像识别,识别率有点感人,基于数据集的关系,大致来说还可行.下面我就继续学习 ...