背景
从传统的单体应用转型spring cloud的朋友都在问我,spring cloud
下的微服务权限怎么管?怎么设计比较合理?从大层面讲叫服务权限,往小处拆分,分别为三块:用户认证
、用户权限
、服务校验
。
用户认证
传统的单体应用可能习惯了session的存在,而到了spring cloud的微服务化后,session虽然可以采取分布式会话来解决,但终究不是上上策。开始有人推行spring cloud security结合很好的oauth2
,后面为了优化oauth 2中access token
的存储问题,提高后端服务的可用性和扩展性,有了更好token验证方式jwt
(json web token)。这里要强调一点的是,oauth2
和jwt
这两个根本没有可比性,是两个完全不同的东西。
oauth2是一种授权框架
,而jwt
是一种认证协议
oauth2认证框架oauth2中包含四个角色:
- 资源拥有者(resource owner)
- 资源服务器(resource server)
- 授权服务器(authorization server)
- 客户端(client)
oauth2包含4种授权模式
- 授权码(认证码)模式 (authorization code)
- 简化(隐形)模式 (impilict
- 用户名密码模式 (resource owner password credential)
- 客户端模式 (client credential)
其中,oauth2的运行流程如下图,摘自rfc 6749:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
+--------+ +---------------+ | |--(a)- authorization request ->| resource | | | | owner | | |<-(b)-- authorization grant ---| | | | +---------------+ | | | | +---------------+ | |--(c)-- authorization grant -->| authorization | | client | | server | | |<-(d)----- access token -------| | | | +---------------+ | | | | +---------------+ | |--(e)----- access token ------>| resource | | | | server | | |<-(f)--- protected resource ---| | +--------+ +---------------+ |
我们在spring cloud oauth2中,所有访问微服务资源的请求都在http header中携带token,被访问的服务接下来再去请求授权服务器验证token的有效性,目前这种方式,我们需要两次或者更多次
的请求,所有的token有效性校验都落在的授权服务器上,对于我们系统的水平扩展成为一个非常大的瓶颈。
jwt认证协议
授权服务器
将用户信息和授权范围序列化后放入一个json字符串,然后使用base64进行编码,最终在授权服务器用私钥对这个字符串进行签名,得到一个json web token
。
假设其他所有的资源服务器都将持有一个rsa公钥,当资源服务器接收到这个在http header中存有token的请求,资源服务器就可以拿到这个token,并验证它是否使用正确的私钥签名(是否经过授权服务器签名,也就是验签)。验签通过,反序列化后就拿到toekn中包含的有效验证信息。
其中,主体运作流程图如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
+-----------+ +-------------+ | | 1 -request authorization | | | |------------------------------------>| | | | grant_type&username&password | |--+ | | |authorization| | 2 -gen | | |service | | jwt | | 3 -response authorization | |<-+ | |<------------------------------------| private key | | | access_token / refresh_token | | | | token_type / expire_in | | | client | +-------------+ | | | | +-------------+ | | 4 -request resource | | | |-----------------------------------> | | | | authorization: bearer access token | |--+ | | | resource | | 5 -verify | | | service | | token | | 6 -response resource | |<-+ | |<----------------------------------- | public key | +-----------+ +-------------+ |
通过上述的方式,我们可以很好地完成服务化后的用户认证。
用户权限
传统的单体应用的权限拦截,大家都喜欢shiro
,而且用的颇为顺手。可是一旦拆分后,这权限开始分散在各个api了,shiro
还好使吗?笔者在项目中,并没有用shiro
。前后端分离后,交互都是token,后端的服务无状态化,前端按钮资源化,权限放哪儿管好使?
抽象与设计
在介绍灵活的核心设计前,先给大家普及一个入门的概念:rbac
(role-based access control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。
rbac其实是一种分析模型,主要分为:基本模型rbac0(core rbac)、角色分层模型rbac1(hierarchal rbac)、角色限制模型rbac2(constraint rbac)和统一模型rbac3(combines rbac)。
核心uml
这是笔者通过多种业务场景后抽象的rbac关系图
类说明
group
群或组,拥有一定数量权限的集合,亦可以是权限的载体。
子类
:user(用户)、role(角色)、position(岗位)、unit(部门),通过用户的特定构成,形成不同业务场景的群或组,而通过对群或组的父类授权,完成了用户的权限获取。
permission
权限,拥有一定数量资源的集成,亦可以是资源的载体。
resources
权限下有资源,资源的来源有:menu(菜单)、button(动作权限)、页面元素(按钮、tab等)、数据权限等
program
程序,相关权限控制的呈现载体,可以在多个菜单中挂载。
常见web程序基本构成
模型与微服务的关系
如果把spring cloud服务化后的所有api接口都定义为上文的resources
,那么我们可以看到这么一个情况。
比如一个用户的增删改查,我们的页面会这么做
页面元素 | 资源编码 | 资源uri | 资源请求方式 |
---|---|---|---|
查询 | user_btn_get | /api/user/{id} | get |
增加 | user_btn_add | /api/user | post |
编辑 | user_btn_edit | /api/user/{id} | put |
删除 | user_btn_del | /api/user/{id} | delete |
在抽象成上述的映射关系后,我们的前后端的资源有了参照,我们对于用户组的权限授权就容易了。比如我授予一个用户增加、删除权限。在前端
我们只需要检验该资源编码
的有无就可以控制按钮的显示和隐藏,而在后端
我们只需要统一拦截判断该用户是否具有uri
和对应请求方式
即可。
至于权限的统一拦截是放置在zuul
这个网关上,还是落在具体的后端服务的拦截器上(filter、inteceptor),都可以轻而易举地实现。不在局限于代码的侵入性。放置zuul流程图如下:
要是权限的统一拦截放置在zuul
上,会有一个问题,那就是后端服务安不安全,服务只需要通过注册中心,即可对其他服务进行调用。这里就涉及到后面的第三个模块,服务之间的鉴权。
服务之间的鉴权
因为我们都知道服务之间开源通过注册中心寻到客户端后,直接远程过程调用的。对于生产上的各个服务,一个个敏感性的接口,我们更是需要加以保护。主题的流程如下图:
笔者的实现方式是基于spring cloud的feignclient inteceprot
(自动申请服务token、传递当前上下文)和mvc inteceptor
(服务token校验、更新当前上下文)来实现,从而对服务的安全性做进一步保护。
结合spring cloud的特性后,整体流程图如下:
优化点
虽然通过上述的用户合法性检验、用户权限拦截以及服务之间的鉴权,保证了api接口的安全性,但是其间的http访问频率
是比较高的,请求数量上来的时候,慢
的问题是就会特别明显。可以考虑一定的优化策略,比如用户权限缓存、服务授权信息的派发与混存、定时刷新服务鉴权token等。
结语
上述是笔者在项目里的大体思路,有兴趣的朋友可以借鉴我的开源项目,欢迎star:
- gitchina:https://gitee.com/minull/ace-security(Jwt、用户权限)
- github:https://github.com/wxiaoqi/ace-security
- gitchina:http://git.oschina.net/geek_qi/ace-gate(服务鉴权)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u011282930/article/details/80131534