源码地址

微服务开发系列:开篇
微服务开发系列:为什么选择 kotlin
微服务开发系列:为什么用 gradle 构建
微服务开发系列:目录结构,保持整洁的文件环境
微服务开发系列:服务发现,nacos 的小补充
微服务开发系列:怎样在框架中选择开源工具
微服务开发系列:数据库 orm 使用
微服务开发系列:如何打印好日志
微服务开发系列:鉴权
微服务开发系列:认识到序列化的重要性
微服务开发系列:设计一个统一的 http 接口内容形式
微服务开发系列:利用异常特性,把异常纳入框架管理之中
微服务开发系列:利用 knife4j,生成最适合微服务的文档

在框架中,使用的鉴权模块是 spring security

1 鉴权模块:gateway

gateway 的模块,涉及到 http 方面的代码,由于是 webflux 架构 ,都与传统的 servlet 相差甚远,因此需要对 webflux 中使用的 reactor 响应式编程有一定的了解。

spring security 最主要的应用模块是 gateway。这里管理了所有的 http 请求,所以在一个中型系统中是最适合鉴权的地方,同时 gateway 也是网关模块。

所有与鉴权相关的类都在包路径 cn.gateway.framework.security 下。

下面是对各个类的说明。

1.1 AuthenticationManager

自定义用户鉴权管理类。

用于对自定义的 cn.framework.common.security.User 扩展字段的验证。

在此类中,校验了 credentialsBeenReset 这个自定义扩展字段,如果为 false,提示前端用户需要进行密码重置,否则无法继续登录。

1.2 LoginConverter

自定义的从 http 请求中获取登录信息的类。

在该类中,除了提供解析请求中的 username 和 password,还增加了对验证码的校验。

是否校验验证码,可以通过配置 gateway.login.verify.enable 选择是否开启,默认不开启。

1.3 SecurityBeanConfig

spring security 需要用的 bean 在此类中定义。

目前只定义了两个 bean:

  1. PasswordEncoder 密码的加密方式
  2. ServerSecurityContextRepository,session 的保存位置

1.4 UserDetailsServiceImpl

用户信息的加载。

在这里定义了根据 username 获取用户信息。

因为用户信息的获取在 business-web 模块,开放 http 接口并不安全,所以使用了 redisson 提供的 RemoteService rpc的方式调用,获取用户信息。

1.5 VerifyCodeController

获取验证的接口,调用此接口来判断是否开启验证码功能,同样是受到 gateway.login.verify.enable  的控制,默认不开启。

在成功获取到验证码之后,会将验证码的代码保存到 websession 中,同时设置 websession 的最大有效时间,也就是验证码的有效时间,通过配置 gateway.login.verify.timeout 控制。

最后,只需要将验证码转化为 base64 返回给前台即可。

1.6 WebfluxSecurityConfig

此类是 spring security 开启的入口类,所有与 spring security 相关的配置都在这里完成。

上面的所有类,都是为此类服务的。

具体有如下功能。

  1. 设置 session 有效时间,通过配置 gateway.session.max-interval-seconds 控制
  2. 设置登录配置,在方法 setLogin,包括 url 路径,登录成功后操作,登录失败后操作
  3. 设置登出配置,在方法 setLogout,包括 url 路径,登录成功后操作
  4. 设置权限,在方法 setPermission,给 url 设置权限验证或者排除权限验证,除此之外,还能够灵活的设置权限,比如包含参数、请求方法、用户角色、用户资源清单等方面限制,如果后续有垂直鉴权的需求,也是在此处完成

2 下游系统

下游系统指的是,所有请求都要经过 gateway 的系统。

在改框架中,不对下游系统做任何权限方便的设置,但还是依赖了 spring security 体系,原因有两个

  1. 防止以后有扩展需求,需要用到
  2. 需要不在代码层面接收来自网关的权限信息,能够通过框架自然完成衔接

下游系统的权限配置全部关闭,通过 framework:cn.framework.config.security.MvcSecurityHttpConfig 完成。

因为完全没有权限验证机制,因此下游系统必须关闭对外部的网络连接,所有的请求都必须经过网关,否则整个系统等于没有权限验证。
在设计的过程中不是没有考虑到,但在搭建的过程中进行了思考与对其它系统的参考,认为没有开启的必要,如果需要开启,上面已经提到过,已经预留了开启方式。

3 认证信息传递

认证信息的生成与传递,全部由 spring security 自动完成,没有自定义代码参与。

认证信息的传递,包含了两种传递渠道

  1. 网关 -> 前台
  2. 网关 -> 下游

3.1 网关 -> 前台

一开始框架采用的方式是使用 cookie 传递到前台,这也是 spring security 的默认传递方式。

但是这样做面临了很多问题。

  1. 日益严格的安全保护,从浏览器到 axios 都对 cookie 进行了严格的限制,即使使用 csrf,也不能完全避免限制。
  2. IE 浏览器在跨域下对 cookie 支持有严重的问题,使用起来非常困难
  3. 前台需要为保留 cookie 做很多定制化的改造

因此,框架中完全抛弃 cookie 的使用,转而使用自定义 header 的方式,参数为 X-Auth-Token

对此,spring security 已经提供了配置的方式。

网关配置在 gateway:cn.gateway.framework.session.WebfluxHttpSessionConfig 类中。

3.2 网关 -> 下游

网关在接收到包含 X-Auth-Token 的请求后,会自动将 X-Auth-Token 转发到下游系统中。

下游系统为了能够方便的获取到认证信息,只需要与网关配置一样的认证信息方式。

下游系统统一配置在 framework:cn.framework.config.session.MvcHttpSessionConfig 类中。

认证信息能够通过 framework:cn.framework.common.security.User#currentUserForMvc 方法方便的获取到认证信息。

如果需要扩展认证信息,比如带上用户机构、用户邮箱等信息,只需要扩展 UserUserDeserializer 两个类即可。


zxdposter
3.9k 声望3.5k 粉丝