使用 Ocelot 匹配路由的方法匹配路由
使用 Ocelot 匹配路由的方法匹配路由
Intro
之前我們在 Ocelot 網(wǎng)關(guān)的基礎(chǔ)上自定義了一個(gè)認(rèn)證授權(quán)的 Ocelot 中間件,根據(jù)請求的路徑和 Method 進(jìn)行匹配,找到對應(yīng)的權(quán)限配置,并判斷是否可以擁有訪問資源的角色,如果沒有則返回 401/403,如果有權(quán)限則轉(zhuǎn)發(fā)到下游服務(wù)。
原來的匹配方式是首先根據(jù)請求路徑和方法完全匹配,如果匹配不到則嘗試使用正則匹配。
我們這次要做的就是將原來的正則匹配替換成 Ocelot 內(nèi)部的路由匹配方式,這樣我們在配置的時(shí)候就不再需要配置兩套了,一邊寫 Ocelot 路由的配置,一邊寫權(quán)限的配置,這樣能減少不少工作量
深入 Ocelot 路由匹配
我們想使用 Ocelot 的路由匹配,首先應(yīng)該了解 Ocelot 的執(zhí)行過程,然后找到對應(yīng)的路由匹配的地方,看路由匹配使用到了哪一個(gè)服務(wù),用這個(gè)服務(wù)在我們自己的業(yè)務(wù)邏輯里匹配即可。
先來看一下 Ocelot 的服務(wù)注冊,Ocelot 的服務(wù)注冊
可以看到主要的服務(wù)注冊代碼應(yīng)該在 OcelotBuilder 中,查看 OcelotBuilder https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DependencyInjection/OcelotBuilder.cs
可以看到,Ocelot 的服務(wù)注冊都在這里, Ocelot 內(nèi)部好多都是基于接口的,所以需要找對應(yīng)的實(shí)現(xiàn)的話可以看它的服務(wù)注冊是注冊的哪一個(gè)服務(wù)即可。
簡單分析一下,Ocelot 的路由匹配過程一定在尋找下游地址的時(shí)候,根據(jù)上游的請求信息(直接請求網(wǎng)關(guān)的請求)匹配,所以我們首先找到 DownstreamRouteFinderMiddleware https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DownstreamRouteFinder/Middleware/DownstreamRouteFinderMiddleware.cs
由上面的代碼,我們可以看到,下游路由地址是通過 IDownstreamRouteFinder 來找下游路由的,轉(zhuǎn)到對應(yīng)的實(shí)現(xiàn)代碼:https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/DownstreamRouteFinder/Finder/DownstreamRouteFinder.cs
這里我們可以看到是通過 IUrlPathToUrlTemplateMatcher 來進(jìn)行路由匹配的,所以我們需要用到這個(gè)服務(wù),然后看這個(gè) Match 方法的參數(shù),前兩個(gè)參數(shù)比較明確,第一個(gè)參數(shù)是上游請求的地址,第二個(gè)參數(shù)是請求的 queryString,第三個(gè)參數(shù)則是 Ocelot 內(nèi)部構(gòu)建出來的路由模板信息 UpstreamPathTemplate,然后我們就需要知道怎么構(gòu)建一個(gè) UpstreamPathTemplate 對象,繼續(xù)探索
直接看 UpstreamPathTemplate,表示一臉懵逼,不知道怎么構(gòu)建, 全局搜素了一下,發(fā)現(xiàn)有一個(gè) IUpstreamTemplatePatternCreator 里面定義了一個(gè) Create 的方法
這個(gè)方法看上去簡單了好多,查看 IReRoute 的定義 https://github.com/ThreeMammals/Ocelot/blob/13.5.2/src/Ocelot/Configuration/File/IReRoute.cs
我們只需要根據(jù)路徑模板構(gòu)建一個(gè) IReRoute 對象即可,Ocelot 中有一個(gè)實(shí)現(xiàn)了 IReRoute 的類 FileReRoute,但是感覺有些復(fù)雜,就沒有用,自定義了一個(gè)類型實(shí)現(xiàn)了 IReRoute
自此,我們就已經(jīng)找到了要使用 Ocelot 路由匹配所需要的服務(wù)了:
IUrlPathToUrlTemplateMatcher
IUpstreamTemplatePatternCreator
使用 Ocelot 路由匹配
上面提到了我們沒有使用 FileReRoute 對象,所以我們就需要自定義一個(gè) 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
總結(jié)
以上是生活随笔為你收集整理的使用 Ocelot 匹配路由的方法匹配路由的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI Boot Camp 分享之 ML.
- 下一篇: 【.NET Core 3.1】 策略授权