Spring Security + OAuth2.0 构建微服务统一认证解决方案(三)
搭建过程可以分为以下几步
- 构建简单的Spring Security + OAuth2.0 认证服务
- 优化认证服务(使用JWT技术加强token,自定义auth接口以及返回结果)
- 配置gateway服务完成简单鉴权功能
- 优化gateway配置(添加复杂鉴权逻辑等等)
(三)配置gateway服务完成JWT简单鉴权功能
之前的网关服务仅仅用做请求的路由转发。现在对网关服务进行,对请求中携带的token进行鉴权。
一. 配置相关依赖
导入spring security和oauth相关依赖,以及JWT相关依赖
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.10.1</version>
</dependency>
要注意的是导入 nimbus-jose-jwt 这个包时,在启动时可能会出现冲突的奇怪问题,详情如下(当时用的是8.17版本)
更新包版本,换成9.10.1就没这个问题了
二. 配置JWT解码需要的公钥获取接口
之前在Auth服务中用私钥在JWT中创建了签名,由此我们在验证时需要用公钥对Token进行验证,防止伪造Token。
Auth服务提供公钥接口
在Auth服务中,由于之前创建好了RSA 密钥的 KeyPair 的 Bean,可以很方便地创建一个接口返回公钥信息
@RestController
public class RSAController {
@Autowired
private KeyPair keyPair;
@GetMapping("/rsa/publicKey")
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
也要记得在spring security的配置中放开权限
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 放开接口权限
.antMatchers("/rsa/publicKey").permitAll()
.anyRequest().authenticated();
}
......
}
gateway服务配置公钥获取url
在yaml中进行配置即可,之后配置好JWT解码,框架会自动去请求公钥验证
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: 'http://localhost:8401/rsa/publicKey'
三. 启用JWT验证
使用 @EnableWebFluxSecurity 注解开启 WebFlux
在config中启用jwt验证
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
// 开启jwt验证
http.oauth2ResourceServer().jwt();
return http.build();
}
}
四. 测试结果
1) 放入之前过期的accessToken请求某接口
这里的Token前缀加上了“Bearer ”,用于定义该Authorization的规范。可以看到结果返回401,错误信息是因为token过期
2)放入错误token
从之前Token中删去一些字符使其失效,再次请求
可以看到返回401,错误信息是token无效,解析失败。
3)放入正确Token
新生成一个token,放入Authorization字段中进行请求,看到通过了校验,可以正常路由并返回结果
五. 后续工作
这只是一个超级简单的gateway鉴权,且只有Authorization字段前缀为“Bearer ”时才开启校验,否则不校验。
如下,随便输入字符串也可以得到结果。
由此,后续可以将鉴权逻辑进行优化
- 增加筛选,将Authorization字段前缀非“Bearer ”开头的请求拦截
- OPTIONS(预检)请求和白名单路径直接放行
- 给URL设置用户访问权限并校验
- 添加自定义gateway filter
Spring Security + OAuth2.0 构建微服务统一认证解决方案(一)
Spring Security + OAuth2.0 构建微服务统一认证解决方案(二)
Spring Security + OAuth2.0 构建微服务统一认证解决方案(四)
github 仓库