前言:之前的文章有讲过微服务的权限系列和网关实现,都是孤立存在,本文将整合后端服务与网关、权限系统。安全权限部分的实现还讲解了基于前置验证的方式实现,但是由于与业务联系比较紧密,没有具体的示例。业务权限与业务联系非常密切,本次的整合项目将会把这部分的操作权限校验实现基于具体的业务服务。
1. 前文回顾与整合设计
在认证鉴权与API权限控制在微服务架构中的设计与实现系列文章中,讲解了在微服务架构中Auth系统的授权认证和鉴权。在微服务网关中,讲解了基于netflix-zuul组件实现的微服务网关。下面我们看一下这次整合的架构图。
整个流程分为两类:
- 用户尚未登录。客户端(web和移动端)发起登录请求,网关对于登录请求直接转发到auth服务,auth服务对用户身份信息进行校验(整合项目省略用户系统,读者可自行实现,直接硬编码返回用户信息),最终将身份合法的token返回给客户端。
- 用户已登录,请求其他服务。这种情况,客户端的请求到达网关,网关会调用auth系统进行请求身份合法性的验证,验证不通则直接拒绝,并返回401;如果通过验证,则转发到具体服务,服务经过过滤器,根据请求头部中的userId,获取该user的安全权限信息。利用切面,对该接口需要的权限进行校验,通过则proceed,否则返回403。
第一类其实比较简单,在讲解认证鉴权与API权限控制在微服务架构中的设计与实现就基本实现,现在要做的是与网关进行结合;第二类中,我们新建了一个后端服务,与网关、auth系统整合。
下面对整合项目涉及到的三个服务分别介绍。网关和auth服务的实现已经讲过,本文主要讲下这两个服务进行整合需要的改动,还有就是对于后端服务的主要实现进行讲解。
2. gateway实现
微服务网关已经基本介绍完了网关的实现,包括服务路由、几种过滤方式等。这一节将重点介绍实际应用时的整合。对于需要修改增强的地方如下:
- 区分暴露接口(即对外直接访问)和需要合法身份登录之后才能访问的接口
- 暴露接口直接放行,转发到具体服务,如登录、刷新token等
- 需要合法身份登录之后才能访问的接口,根据传入的Access token进行构造头部,头部主要包括userId等信息,可根据自己的实际业务在auth服务中进行设置。
- 最后,比较重要的一点,引入Spring Security的资源服务器配置,对于暴露接口设置permitAll(),其余接口进入身份合法性校验的流程,调用auth服务,如果通过则正常继续转发,否则抛出异常,返回401。
绘制的流程图如下:
2.1 permitAll实现
对外暴露的接口可以直接访问,这可以依赖配置文件,而配置文件又可以通过配置中心进行动态更新,所以不用担心有hard-code的问题。
在配置文件中定义需要permitall的路径。
1
|
auth:
|
服务启动时,读入相应的Configuration,下面的配置属性读取以auth开头的配置。
1
|
|
当然还需要有PermitAllUrlProperties对应的实体类,比较简单,不列出来了。
2.2 加强头部
Filter过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源进行拦截。这边使用Filter进行头部增强,解析请求中的token,构造统一的头部信息,到了具体服务,可以利用头部中的userId进行操作权限获取与判断。
1
|
public class HeaderEnhanceFilter implements Filter {
|
上面代码列出了头部增强的基本处理流程,将isPermitAllUrl的请求进行直接传递,否则判断是不是符合规范的头部,然后解析authorization中的token,构造USER_ID_IN_HEADER。最后为了适配,设置匿名头部。
需要注意的是,HeaderEnhanceFilter也要进行注册。Spring 提供了FilterRegistrationBean类,此类提供setOrder方法,可以为filter设置排序值,让spring在注册web filter之前排序后再依次注册。
2.3 资源服务器配置
利用资源服务器的配置,控制哪些是暴露端点不需要进行身份合法性的校验,直接路由转发,哪些是需要进行身份loadAuthentication,调用auth服务。
1
|
|
资源服务器的配置大家看了笔者之前的文章应该很熟悉,此处不过多重复讲了。关于ResourceServerSecurityConfigurer配置类,之前的安全系列文章已经讲过,ResourceServerTokenServices接口,当时我们也用到了,只不过用的是默认的DefaultTokenServices。这边通过自定义的CustomRemoteTokenServices,植入身份合法性的相关验证。
当然这个配置还要引入Spring Cloud Security oauth2的相应依赖。
1
|
<dependency>
|
2.4 自定义RemoteTokenServices实现
ResourceServerTokenServices接口其中的一个实现是RemoteTokenServices。
Queries the /check_token endpoint to obtain the contents of an access token.
If the endpoint returns a 400 response, this indicates that the token is invalid.
RemoteTokenServices主要是查询auth服务的/check_token端点以获取一个token的校验结果。如果有错误,则说明token是不合法的。笔者这边的的CustomRemoteTokenServices实现就是沿用该思路。需要注意的是,笔者的项目基于Spring cloud,auth服务是多实例的,所以这边使用了Netflix Ribbon获取auth服务进行负载均衡。Spring Cloud Security添加如下默认配置,对应auth服务中的相应端点。
1
|
security:
|
至于具体的CustomRemoteTokenServices实现,可以参考上面讲的思路以及RemoteTokenServices,很简单,此处略去。
至此,网关服务的增强完成,下面看一下我们对auth服务和后端backend服务的实现。
强调一下,为什么头部传递的userId等信息需要在网关构造?读者可以自己思考一下,结合安全等方面,