1. 需求
-
增加产品概念
之前写的auth包括用户、组织、角色、权限等关系,在新的业务中,又提出了产品、项目等概念,要求:
- 不同的产品使用同一套用户系统,一个账户可以在多个产品中使用
- 目前的产品线中都有组织概念
- 不同产品的角色权限系统是不同的,但有相似的用户、组织、权限管理的功能
-
业务使用方式
方式1
- 业务人员在后台给用户创建了组织,并设置开通的产品,用户可以对相应的产品进行访问
方式2
- 用户自己在一个产品上创建了组织,邀请了成员,设置了角色
- 又想使用另外一个产品,系统返回尚未开通本产品,是否开通
- 用户选择“是”,这时候组织又开通了另外一个产品线
不论哪种方式都应该具备:
- 不同的产品之间共享用户、组织、角色(部分)等内容
- 角色分成公共的与产品特有的,公共角色指的是组织管理相关的橘色,在不同产品间互通,特有的角色是与产品的功能相关,产品间不互通。
- 用户在不同产品之间访问可以应该是单点登录的,即:一个产品登录,其他产品都登录
- 用户在不同产品产生的数据是独立的,不会出现在1个产品产生的数据,在另外一个产品中还能看到,即使是相同的功能。
-
服务维护方式
有新的产品上线
- 将服务启动起来,包括数据库、服务等
- 向auth中心注册新产品,包括新产品的信息(code、url)、产品的权限、产品独有的角色、角色(包括公共与独有)与权限的关系等内容
- 配置网关,将域名指向相应的服务
- 进行相应的开通工作
- 用户访问新产品
-
其他
-
PMS与PMP带来的启示
- 组织切换互通:这种互通问题依然会存在,组织在产品之前,切换了组织也就切换了产品关系,能否访问该产品都受控于组织
- 产品线数据互通:这个可以做到,首先是产品线中的功能尽量不交叉,如果交叉,部署新的服务,独立数据库,做到数据隔离。
-
个人空间
-
个人空间给独特的组织标识
-
个人空间受控于产品,某些产品没有个人空间
-
获取用户所在组织时,根据不同产品,确定是否返回个人空间
-
项目
- 有的产品有项目,有的没有项目。项目属于产品内部功能,不做产品间的同步;
- 项目中有人员,属于产品内功能;项目中的角色由组织控制,属于公共功能,项目中人员登录该系统时,看到的菜单与组织的看到的不同;
- 项目有生命周期;
- 项目中的功能一般与公司中的功能相对应,项目侧汇报,公司侧统计。
- 项目中功能的鉴权应该是:人员、项目、角色
- 项目可以进行切换
-
后台管理系统
- 把后台看成一个产品
- 后台中负责各种管理工作
- 这个产品仅对多邦组织赋予
2. 分析
这里要做的,其实是一个用于多系统的鉴权中心,用于B端用户的单点登录及授权。
这里有两种方案可以来做,第一种以用户为中心,用户与产品做关联:
- 把用户系统独立出来,维护用户信息,做登录、退出等工作,单独的服务;
- 组织、权限、产品线抽象到一起,一个代码,多个产品起多个服务,不同的数据;
- 多个系统先通过nginx,然后再通过各自的gateway,在gateway中进行认证与鉴权
第二种以组织为中心,组织与产品做关联:
- 用户、组织、角色、权限、产品都在一起成为独立与产品的权限中心
- 组织与产品关联,给组织开哪些产品先
以目前看,我们的潜在用户有2类:小公司有多个项目情况,大的项目情况,不论哪种情况都是以组织为中心的,所以使用第2种方案更好一些。
这样就来看看常用的单点登录。
单点登录的方式是多系统共享用户资源的OAuth方式,除此之外各个系统之间相互独立。
对应于B端,不仅仅是用户资源,组织、角色、权限等都是共享的资源,需要考虑的就会更多一些。
目前各个系统都是同一顶级域名下的不同子域名形式。
基于以上条件,统一的auth-server来对各个产品鉴权,它们使用同一token,虽然是不同的产品线,但对于后端而言,它们更像是一个系统,类似于将之前PMS中不同模块用多个前端封装成不同产品。
3. 设计
3.1 结构
目前的网关是做限流、鉴权等工作的,而不同的产品其鉴权的策略不同,如有项目的产品与没有项目的产品就存在差异:
nginx做最前端的网关,各个产品使用自己的网关,鉴权在各个产品线自己的网关中完成;
最外层的nginx也可以不要,各个产品使用自己网关即可,因为他们往往并不是部署在一台机器上;
整个系统使用一个域名,不同产品使用一个子域名,不同产品中的各个服务通过路由来做区分;
总体的结构示意图:
在这里将用户、组织、产品、角色、权限抽象成一个auth;
将项目、项目与组织关系、项目与用户关系、项目中角色抽象成独立的prioject-auth,这块逻辑既可以包含在各个server内部,也可以是单独的server,看以后服用的情况。这里按单独server来构思。
auth关系图:
project-auth关系图:
流程一般为:由各自的客户端出发,进入网关,然后进入业务server,在业务server中,向project-auth进行鉴权
3.2 流程
这样,与单系统的鉴权相比,除了初次的一些重定向略有不同,其余的基本相同。
4. 鉴权
认证过程已经在Gateway文章中做了介绍,这里不在赘言了,对于鉴权,这里再说一下。
-
interceptor
这里将鉴权interceptor封装到了common包中,这样common包需要依赖Auth进行用户权限的查询,这里使用Feigin。
-
app.authorization配置项
考虑到有的情况下可能没有鉴权,所在在追加addInterceptor之前,进行该配置项的判断,只有为true时,才可以使用
使用@ConditionalOnProperty,参考
-
增加AuthorizationConfig
考虑到一来每次在业务服务中addInterceptor麻烦,二来project的Authorization并不是相同的逻辑,这里增加了AuthorizationAutoConfig来自动进行addInterceptor,并且只有ConditionalOnSingleCandidate时,才自动注入。这样以后如果有project,在各自的project实现一个AuthorizationConfig就好。
出现了循环依赖的问题,增加@Lazy解决,参考;
出现ConditionalOnMissBean不好使,发现其自身也在其中,使用@ConditionalOnSingleCandidate解决,参考。
-
这样使用鉴权的流程为
- 依赖 common
- 配置 app.authorization=true
- application启用Feigin:EnableFeignClients(basePackages = {})