ocelot 自定义认证和授权

Intro

最近又重新启动了网关项目,服务越来越多,每个服务都有一个地址,这无论是对于前端还是后端开发调试都是比较麻烦的,前端需要定义很多 baseUrl,而后端需要没有代码调试的时候需要对每个服务的地址都收藏着或者记在哪里,用的时候要先找到地址,甚是麻烦,有了网关之后,所有的 API 就有了统一的入口,对于前端来说就不需要维护那么多的 baseUrl,只需要网关的地址即可,对于后端来说也是同样的。

Ocelot 简介

Ocelot是一个用.NET Core实现并且开源的API网关,它功能强大,包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断等功能,这些功能只都只需要简单的配置即可完成。

自定义认证授权

自定义认证授权思想,这里的示例是一个基于用户角色授权的示例:

  1. 基于 url 以及 请求 Method 查询需要的权限
  2. 如果不需要用户登录就可以访问,就直接往下游服务转发
  3. 如果需要权限,判断当前登录用户的角色是否可以以当前 Method 访问当前路径
  4. 如果可以访问就转发到下游服务,如果没有权限访问根据用户是否登录,已登录返回 403 Forbidden,未登录返回 401 Unauthorized

Ocelot 的 认证授权不能满足我的需要,于是就自己扩展了一个 Ocelot 的中间件

示例代码

  1. public class ApiPermission
  2. {
  3. public string AllowedRoles { get; set; }
  4. public string PathPattern { get; set; }
  5. public string Method { get; set; }
  6. }
  7. public class UrlBasedAuthenticationMiddleware : Ocelot.Middleware.OcelotMiddleware
  8. {
  9. private readonly IConfiguration _configuration;
  10. private readonly IMemoryCache _memoryCache;
  11. private readonly OcelotRequestDelegate _next;
  12. public UrlBasedAuthenticationMiddleware(OcelotRequestDelegate next, IConfiguration configuration, IMemoryCache memoryCache, IOcelotLoggerFactory loggerFactory) : base(loggerFactory.CreateLogger<UrlBasedAuthenticationMiddleware>())
  13. {
  14. _next = next;
  15. _configuration = configuration;
  16. _memoryCache = memoryCache;
  17. }
  18. public async Task Invoke(DownstreamContext context)
  19. {
  20. var permissions = await _memoryCache.GetOrCreateAsync("ApiPermissions", async entry =>
  21. {
  22. using (var conn = new SqlConnection(_configuration.GetConnectionString("ApiPermissions")))
  23. {
  24. entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
  25. return (await conn.QueryAsync<ApiPermission>("SELECT * FROM dbo.ApiPermissions")).ToArray();
  26. }
  27. });
  28. var result = await context.HttpContext.AuthenticateAsync(context.DownstreamReRoute.AuthenticationOptions.AuthenticationProviderKey);
  29. context.HttpContext.User = result.Principal;
  30. var user = context.HttpContext.User;
  31. var request = context.HttpContext.Request;
  32. var permission = permissions.FirstOrDefault(p =>
  33. request.Path.Value.Equals(p.PathPattern, StringComparison.OrdinalIgnoreCase) && p.Method.ToUpper() == request.Method.ToUpper());
  34. if (permission == null)// 完全匹配不到,再根据正则匹配
  35. {
  36. permission =
  37. permissions.FirstOrDefault(p =>
  38. Regex.IsMatch(request.Path.Value, p.PathPattern, RegexOptions.IgnoreCase) && p.Method.ToUpper() == request.Method.ToUpper());
  39. }
  40. if (!user.Identity.IsAuthenticated)
  41. {
  42. if (permission != null && string.IsNullOrWhiteSpace(permission.AllowedRoles)) //默认需要登录才能访问
  43. {
  44. //context.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "Anonymous") }, context.DownstreamReRoute.AuthenticationOptions.AuthenticationProviderKey));
  45. }
  46. else
  47. {
  48. SetPipelineError(context, new UnauthenticatedError("unauthorized, need login"));
  49. return;
  50. }
  51. }
  52. else
  53. {
  54. if (!string.IsNullOrWhiteSpace(permission?.AllowedRoles) &&
  55. !permission.AllowedRoles.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Any(r => user.IsInRole(r)))
  56. {
  57. SetPipelineError(context, new UnauthorisedError("forbidden, have no permission"));
  58. return;
  59. }
  60. }
  61. await _next.Invoke(context);
  62. }
  63. }

认证授权之后

经过上面的认证授权之后,就可以往下游转发请求了,下游的服务有的可能会需要判断用户的角色或者需要根据用户的 userId 或者 Name 或者 邮箱去检查某些数据的权限,这里就需要把在网关完成认证之后,得到的用户信息传递给下游服务,这里我选择的是通过请求头把用户信息从网关服务传递到下游服务, Ocelot 可以把 Claims 中的信息转换到 Header ,详细参考Ocelot文档,但是实现有个bug,如果有多个值他只会取第一个,详见issue,可以自己扩展一个 ocelot 的中间件替换掉原有的中间件。

传递到下游服务之后,下游服务在需要用户信息的地方就可以从请求头中获取用户信息,如果下游服务比较复杂,不方便改动的话可以实现一个自定义的请求头认证,可以参考我的这一篇文章

Memo

如果有什么问题或建议,欢迎提出一起交流

ocelot 自定义认证和授权的更多相关文章

  1. spring security 3 自定义认证,授权示例

    1,建一个web project,并导入所有需要的lib. 2,配置web.xml,使用Spring的机制装载: <?xml version="1.0" encoding=& ...

  2. 最简实例演示asp.net5中用户认证和授权(4)

    上篇: 最简实例演示asp.net5中用户认证和授权(3) 上面我们把自定义认证和授权的相关的最小基础类和要实现的接口都实现了,下面就是如何来进行认证和授权的配置. 首先我们要告诉系统,我们的用户和角 ...

  3. Shiro 自定义登陆、授权、拦截器

    Shiro 登陆.授权.拦截 按钮权限控制 一.目标 Maven+Spring+shiro 自定义登陆.授权 自定义拦截器 加载数据库资源构建拦截链 使用总结: 1.需要设计的数据库:用户.角色.权限 ...

  4. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(四)

    在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证.在 ...

  5. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)

    好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名<Angular单页面应用基于Ocelot API网关与IdentityServer4+ASP.NET Iden ...

  6. Ocelot简易教程(五)之集成IdentityServer认证以及授权

    Ocelot简易教程目录 Ocelot简易教程(一)之Ocelot是什么 Ocelot简易教程(二)之快速开始1 Ocelot简易教程(二)之快速开始2 Ocelot简易教程(三)之主要特性及路由详解 ...

  7. spring-security-4 (5)spring security Java配置实现自定义表单认证与授权

    前面三篇讲解了spring security的搭建以及简单的表单认证与授权原理.本篇将实现我们自定义的表单登录与认证.  本篇不会再讲项目的搭建过程,因为跟第二节的搭建如出一辙.本篇也不会将项目中所有 ...

  8. Ocelot(四)- 认证与授权

    Ocelot(四)- 认证与授权 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10932805.html 源码地址:http ...

  9. [转载]Ocelot简易教程(五)之集成IdentityServer认证以及授权

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9807125.html 最近比较懒,所以隔了N天才来继续更新第五篇Ocelot简易教程,本篇教程会先简单介 ...

随机推荐

  1. Java进阶篇设计模式之八 ----- 责任链模式和命令模式

    前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...

  2. 轻量级原生 ajax 函数,支持 get/array post/array post/json

    原生js封装 function ajaxRequest(type, url, data, callback, failCallBack, header, dataType) { var url_enc ...

  3. 搜狗输入法与VS快捷键有冲突_处理办法

    前言:搜狗输入法是大家常用的文字输入工具,但是在开启输入法的时候,VS的一些快捷键无法正常使用,如智能提示快捷键:Ctrl+.,这就非常尴尬了,除非把输入法切换成英文或者卸载搜狗改别的输入法,一个是切 ...

  4. 【代码总结● Swing中的一些操作与设置】

    Swing中设置关闭窗口验证与添加背景图片 package com.swing.test; import java.awt.EventQueue; import java.awt.Image; imp ...

  5. Asp.NetCore轻松学-配置服务 apollo 部署实践

    前言     Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置 ...

  6. SQL Server使用sp_rename重命名约束注意事项

    在SQL Server中,我们可以使用sp_name这个系统存储过程重命名数据库中对象的名称. 此对象可以是表. 索引. 列. 别名,约束等数据类型(具体可以参考官方文档).上周在使用这个函数重构数据 ...

  7. NSTimer循环引用的几种解决方案

    前言 在iOS中,NSTimer的使用是非常频繁的,但是NSTimer在使用中需要注意,避免循环引用的问题.之前经常这样写: - (void)setupTimer { self.timer = [NS ...

  8. Visual Studio Code-批量添加或删除注释行

    小技巧一例,批量删除Visual Studio code或notepad++注解信息,便于读取有效代码或文本信息,具体操作如下: Visual Studio Code批量删除注解行信息: 在VS Co ...

  9. Linux 开启和关闭 Ping 操作

    Linux 默认是开启 ping 操作的,通过以下两种方式可以开启和关闭 ping 操作 . 1.修改内核参数 通过内核参数设置也有两种方式,一种是临时修改,一种是永久修改. 1.1 临时设置 PIN ...

  10. SQL Server 检测到基于一致性的逻辑 I/O 错误 pageid 不正确

    最近在查询SQL时遇到SQL文件错误,可能是文件数据已损坏.解决过程分享给大家. 问题描述 消息 824,级别 24,状态 2,第 1 行SQL Server 检测到基于一致性的逻辑 I/O 错误 p ...