书接上文,上回咱们说到了《【Blog.Core开源】网关统一集成下游服务文档》,已经将多个下游服务统一集成到了网关里,并且也把接口文档Swagger给集成了,那今天就说一下认证和鉴权相关的话题。

继续说下故事背景

在平时开发的时候,特别是有网关的情况下,经常会遇到一个不可避免的话题,就是网关到底要不要帮下游处理某些业务逻辑的问题,比如说认证鉴权、审计日志、当前用户信息获取,白名单等等。

这里其实见仁见智,同时也要考虑各个项目的具体架构设计和需要,我个人的习惯还是网关要轻一些,什么叫轻一些呢,拿BlogCore举例,认证走的是Ids4的统一认证平台,从平台那里得到令牌Token,然后经过网关走到BlogCore,解析,并走具体的自定义授权逻辑,因为这里涉及到动态菜单权限配置,所以很少会放到网关里处理,毕竟每个下游服务都可能会有自己的那部分逻辑。其实除了授权这块,还有一些数据,比如当前用户的私密信息,例如手机号之类的,这个phone肯定不能放到token里的,因为token虽然有过期时间,但是就算是失效,还是可以解密出来的,放到公网上的令牌基本都是只放一些非私密的个人信息,比如uid或者是roleId,实在有需要也可以在token里放部门的id的,这也无可厚非,但是phone和address是万万不能放到token里的。

那么问题来了,phone和address我们到底应该从哪里获取?上边的菜单权限大家已经达成共识,就是放到下游,让下游服务自己来处理,那根据token中的uid来获取phone信息,就需要考虑下了,很多人说放网关呗,每次请求查库等操作,然后放到header里传递给下游,这也是一个方案,今天也会给大家讲讲怎么获取,怎么传。

当然我个人的意见还是网关仅仅是解析token里有的,传递给下游,至于查库的那些,还是下游获取吧,这是我的个人意见,并不是完全正确。为什么呢,大家想想,咱们在网关里写拦截器或者中间件,每次接口请求,都根据header中的token来查库,这样不管下游需不需要,不管下游接口是不是匿名都去查库一下,会造成资源浪费,比如我就想搜索下list,每次都查询下当前人的user信息,似乎没那么必要,特别是list页面高并发的时候,是不是不太好,当然这样的好处就是对下游方便且能做详细的审计日志。

今天咱们就说下如何自定义拦截器传递自定义claim信息给下游。

01

PART

网关自定义认证处理器

在网关中注册认证服务,并设计处理器,实现认证授权拦截,比如说token是否可以正常的解密等,用来判断token的有效性等,也可以查询数据库,获取私密信息:

services.AddAuthentication().AddScheme<AuthenticationSchemeOptions, CustomAuthenticationHandler>(Permissions.GWName, _ => { });

然后具体的处理器,大家根据需求自定义即可,注意把信息放到Claims里,不仅可以在当前网关的其他地方获取,从而减少二次请求的情况。也可以传递给下游服务。

public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{public CustomAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,ILoggerFactory logger,UrlEncoder encoder,ISystemClock clock) : base(options, logger, encoder, clock){}protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){// 可以查询数据库等操作// 获取当前用户不能放到token中的私密信息var userPhone = "15010000000";var claims = new List<Claim>(){new Claim("user-phone", userPhone),new Claim("gw-sign", "gw")};var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));var ticket = new AuthenticationTicket(principal, Scheme.Name);await Task.CompletedTask;return AuthenticateResult.Success(ticket);}
}

内容很简单,就是一个普通的处理器,那接下来就是看如何把Claim给传给下游服务了。

02

PART

对下游服务开启认证处理器

Ocelot已经做好了配置,就像是自定义响应处理器一样,认证的也可以直接配置:

// blog-svc
{"UpstreamPathTemplate": "/svc/blog/{url}","UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],"LoadBalancerOptions": {"Type": "RoundRobin"},"DownstreamPathTemplate": "/svc/blog/{url}","DownstreamScheme": "http","DownstreamHostAndPorts": [{"Host": "localhost","Port": 9291}],// 直接配置认证Key即可"AuthenticationOptions": {"AuthenticationProviderKey": "GW"}
},

也可以有更多的参数配置,具体可以参考官网:

https://ocelot.readthedocs.io/en/latest/features/configuration.html?highlight=AuthenticationOptions#configuration

03

PART

Ocelot将Claim传递下游

还是在Ocelot的官网上可以看到很多Demo,我只配置三项,1、分别是动态从Claim中获取并用Request的Header传值,2、直接在Request中传递固定Header值,3、获取下游服务的Response的Header给上游网关。

其中第三点还是很有用的,比如我们以后的Skywalking中,如果某次链路请求报错了,但是又想快速的定位,所以就需要用户给我们提供当前操作的标识,有时候是uid,有时候是url,这两个都不是很直观。通过配置Ocelot,正好可以从下游服务的response的header中返给前端,用户就能提供了,更加快速方便的定位问题。

// blog-svc
{"UpstreamPathTemplate": "/svc/blog/{url}","UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],"LoadBalancerOptions": {"Type": "RoundRobin"},"DownstreamPathTemplate": "/svc/blog/{url}","DownstreamScheme": "http","DownstreamHostAndPorts": [{"Host": "localhost","Port": 9291}],// 添加到headers// 从claims中获取"AddHeadersToRequest": {"user-phone": "Claims[user-phone] > value","gw-sign": "Claims[gw-sign] > value"},// 从上游网关的request的header中"UpstreamHeaderTransform": {"custom-key": "blog.gateway"},// 从下游服务的response的header中"DownstreamHeaderTransform": {"down-app": "{para-down-app}","trace-id": "Trace-Id"},"AuthenticationOptions": {"AuthenticationProviderKey": "GW"}
},

在上边注释的三块,就是常见的三种方案。

04

PART

下游服务查看具体效果

在BlogCore服务中,valueController中测试下是否传递了具体的参数:

[HttpGet]
public MessageModel<List<ClaimDto>> MyClaims()
{return new MessageModel<List<ClaimDto>>(){success = true,response = (_user.GetClaimsIdentity().ToList()).Select(d =>new ClaimDto{Type = d.Type,Value = d.Value}).ToList()};
}

其中获取Claim方法,也获取了下header中其他的参数:

public IEnumerable<Claim> GetClaimsIdentity(){var claims = _accessor.HttpContext.User.Claims.ToList();var headers = _accessor.HttpContext.Request.Headers;foreach (var header in headers){claims.Add(new Claim(header.Key, header.Value));}return claims;}

这里有一个小注意事项:

如果下游服务是加权的,可以直接通过swagger添加token的方式,获取claims信息,但是接口是匿名的,那swagger是不会传递token信息的,我们可以用postman测试,一样的效果,毕竟前端Vue.js也是我们手动传递的。

关于swagger不加权就不传递token这个问题,以后我会优化下,写个扩展中间件。

查看下具体的情况:

携带上token以后,发起请求,无论是自定义固定的参数还是Claims中的变量都传给了下游服务,并且下游的Response的Header也有了值。

好啦,网关系列的分享就先到这里了,咱们下次再见,说说注册中心集成功能。

【Blog.Core开源】网关自定义认证鉴权与传参相关推荐

  1. 认证鉴权对于 API 网关的重要性

    认证鉴权作为 API 网关不可或缺的能力,已然成为用户在选型 API 网关时考量的重要因素之一. 作者钱勇,API7.ai 开发工程师,Apache APISIX Committer 在当下云原生越发 ...

  2. 开源OA协同办公搭建教程:使用认证鉴权对服务访问进行限制(invoke)

    本篇文章介绍的是开源的协同办公项目O2OA如何使用认证鉴权对服务访问进行限制(invoke). 默认情况下创建的服务是允许匿名访问的,这样创建的服务可以直接通过url访问执行,如果需要进行鉴权限制,那 ...

  3. 微服务认证鉴权-API网关

    认证:验证这个用户是谁 鉴权:用户有哪些资源权限(页面.按钮.超链接.接口.接口字段) 授权:为用户添加资源权限 方案:客户端Token(JWT) 流程: 1.用户登录发起认证请求,认证服务执行认证流 ...

  4. Ocelot(一)- .Net Core开源网关

    Ocelot - .Net Core开源网关 作者:markjiang7m2 原文地址:http://letyouknow.net/ocelot/ocelot-tutorial-1.html 源码地址 ...

  5. 【Blog.Core开源】框架集成部门权限

    (Blog.Core框架功能点概述) Blog.Core开源四年啦,一行行代码凝结了大家的热情和心血,基本功能骨架已完成,欢迎更多的公司和企业使用哟.真实公司留言盖楼可获得一对一技术指导: https ...

  6. 认证鉴权与API权限控制在微服务架构中的设计与实现(一)

    作者: [Aoho's Blog] 引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的第一篇,本系列预计四篇文章讲解微服务下的认证鉴权与API权限控制的实现. 1. ...

  7. 微服务网关限流鉴权-wei-fu-wu-wang-guan-xian-liu--jian-quan

    title: 微服务网关限流&鉴权 date: 2022-01-06 14:40:45.047 updated: 2022-01-06 14:40:45.047 url: https://ww ...

  8. 认证鉴权与API权限控制在微服务架构中的设计与实现

    引言: 本文系<认证鉴权与API权限控制在微服务架构中的设计与实现>系列的第一篇,本系列预计四篇文章讲解微服务下的认证鉴权与API权限控制的实现. 1. 背景 最近在做权限相关服务的开发, ...

  9. Springboot系列之Shiro、JWT、Redis 进行认证鉴权

    Springboot系列之Shiro.JWT.Redis 进行认证鉴权 Shiro架构 Apache Shiro是一个轻量级的安全框架 Shiro可以非常容易的开发出足够好的应用,其不仅可以用在Jav ...

最新文章

  1. 程序员修炼之路:你该知道的 7 个必经阶段
  2. SQL : 在SQL Server 2008(Or Express)中如何Open并编辑数据表【转】
  3. python print换行_Python中九九乘法表与古诗对话机器人及sep-end值
  4. oracle天数加个随机数,如何给一个表某列加上指定的随机数
  5. ElasticSearch和solr的对比
  6. “天问一号”成功发射,马斯克点赞:非常振奋人心
  7. Notes on how to use Webots, especially how to make a robot fly in the air
  8. JDBC 与ODBC的区别
  9. 刚开始学习.NET 怎么样能使自己学习的更快点啊?
  10. mac M1 下安装docker 及相关镜像
  11. 解决 Win11 开机ctfmon.exe不能自启
  12. 电子教室的功能有哪些-极域电子教室
  13. fd在python_python中fd()是什么
  14. ac服务器自动掉线,AC68U经常掉线重连 什么原因?
  15. 使用vscode开发apicloud
  16. 可视化IDE低代码开发平台
  17. 手机3D的新境界:Omnia II 是3D方面的力作!!
  18. Java设计模式 -11- 外观模式(Facade模式)
  19. 开局觉醒天道酬勤天赋(二)
  20. std::function和std::bind用法

热门文章

  1. saltstack 安装nginx
  2. hierarchyviewer
  3. postfix搭建及配置
  4. 51中断编程c语言,[新人求指教]51C语言编程可否用中断令循环结束提早结束
  5. Maven打包小技巧--持续更新
  6. Hadoop3.0 WordCount测试一直Accept 状态,Nodes of the cluster 页面node列表个数为0
  7. shell脚本--cut命令
  8. 反射封装工具类-----零SQL插入
  9. picturebox 图片自适应
  10. poj 2886 Who Gets the Most Candies?(线段树)