OAuth2鉴权流程
其实和认证相对的,还有鉴权流程,鉴权是需要资源服务器配合的,由于资源服务器是真正的业务服务,所以会有很多,所以资源服务器的配置是必须抽出来的。
我希望在微服务每个服务开发的过程中,只需要在自己的工程里引入依赖包,并做简单配置,即可作为资源服务器加入整个SAS的鉴权体系中来,所以资源服务器的配置部分写入公共包。
1.鉴权总流程
其实与AuthorizationServerConfiguration类似,资源服务器也有着掌管主要流程的配置类,
ResourceServerConfiguration也是配置返回SecurityFilterChain来实现的
.oauth2ResourceServer(oauth2 -> oauth2
.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
.bearerTokenResolver(dmsBearerTokenExtractor))
opaqueToken其实就是不透明令牌的处理,
Introspector指定了校验token的处理方式,
bearerTokenResolver是定义了如何从请求中获取token
其实简化一下流程就是
+-----------------+
| |
| 客户端应用 |
| (Web/移动端/API)|
+--------+--------+
|
| 1. 发送请求(携带Access Token)
v
+-------------------------------+
| |
| DmsBearerTokenExtractor |
| (提取请求中的Bearer Token) |
+---------------+---------------+
|
| 2. 提取出Access Token
v
+-------------------------------+
| |
| OpaqueTokenIntrospector |
| (自定义不透明令牌解析器) |
| - 校验Token有效性 |
| - 解析用户信息和权限 |
+---------------+---------------+
|
+-------+-------+
| |
v v
Token有效? Token无效?
| |
| |
v v
+----------------+ +---------------------------+
| | | |
| 授权成功 | | ResourceAuthExceptionEntryPoint |
| 进入Controller | | (返回401/403异常响应) |
| 或方法级安全 | | |
+--------+-------+ +---------------------------+
|
v
+----------------+
| |
| 资源服务器 |
| 返回受保护资源 |
| 给客户端 |
+----------------+
其实这其中最重要的就是DmsCustomOpaqueTokenIntrospector这个类
1.它做了什么呢?验证令牌有效 + 获取关联信息 + 组装用户权限
接下来Introspector返回的用户和权限信息会写入每个请求(request)自己的 SecurityContext中。
2.它是怎么获取到的?认证过程中authorizationService会持久化token,我们选择的redis保存,所以在资源服务器中,可以调用authorizationService.findByToken,然后组装对象返回,然后由BearerTokenAuthenticationFilter(OAuth2框架标准方法)放入上下文;3.BearerTokenAuthenticationFilter它实际上控制了整个 token 校验和认证流程的调用顺序
2.注解引入
为了方便使用,参考了市面上比较流行的框架解决方案,注解鉴权和内部方法调用封装鉴权
HasPermission注解
它是基于 Spring Security 的 @PreAuthorize实现的,
例如@HasPermission("user:list,user:create")加在了controller接口方法上
Spring 会解析 @pms.hasPermission('user:list,user:create'.split(','))
拿到当前用户的 Authentication(从 SecurityContextHolder)
调用 pms.hasPermission(String[] permissions) 方法判断是否有权限
Inner注解
带 @Inner 注解的方法/类,只允许内部服务调用,外部请求或直接浏览器访问会被拒绝。
如果你希望实现内部调用不鉴权,就需要发起者加上@NoToken 接口提供方加上@Inner
@Inner 的设计初衷是 只允许内部服务调用
@EnableDmsFeignClients注解
当你的项目需要通过 Feign 调用其他服务(即 “请求别人”)时,需要在配置类上添加这个注解来启用相关功能。