搭建過程可以分為以下幾步
- 構建簡單的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 倉庫