OAuth + Security – 3 – JWT令牌
- 2020 年 6 月 2 日
- 筆記
- OAuth+Security
為什麼使用JWT令牌
在上面的資源伺服器中,通過配置,我們了解到,當我們拿著token去獲取資源時,程式會先去調用遠程認證伺服器的端點去驗證解析token,或者在本地解析校驗token,這樣毫無疑問,當訪問量過大的時候,對認證伺服器的壓力可想而知,所以為了解決上面的問題,我們採用JWT令牌格式,可以優化上面的問題。
令牌採用JWT格式即可解決上邊的問題,用戶認證通過會得到一個JWT令牌,JWT令牌中已經包括了用戶相關的資訊,客戶端只需要攜帶JWT訪問資源服務,資源服務根據事先約定的演算法自行完成令牌校驗,無需每次都請求認證服務完成授權。
改造認證伺服器
- 修改TokenConfig類,如下:
@Configuration
public class TokenConfigure {
private static final String SIGNING_KEY = "dimples";
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//對稱秘鑰,資源伺服器使用該秘鑰來驗證
converter.setSigningKey(SIGNING_KEY);
return converter;
}
}
- 修改認證伺服器的配置
private JwtAccessTokenConverter jwtAccessTokenConverter;
//通過構造方法注入
...
/**
* 修改
* 令牌管理服務
*
* @return TokenServices
*/
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices services = new DefaultTokenServices();
// 客戶端詳情服務
services.setClientDetailsService(clientDetailsService);
// 支援令牌刷新
services.setSupportRefreshToken(true);
// 令牌存儲策略
services.setTokenStore(tokenStore);
// 配置令牌增強 JWT
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter));
services.setTokenEnhancer(tokenEnhancerChain);
// 令牌默認有效期2小時
services.setAccessTokenValiditySeconds(7200);
// 刷新令牌默認有效期2天
services.setRefreshTokenValiditySeconds(259200);
return services;
}
- 最後別忘了在pom中添加JWT的依賴,否則項目將會報錯
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
測試結果如下:
可以使用OAuth的/oauth/check_token端點來解析驗證一下該token
改造資源伺服器
當我們使用了JWT令牌以後,由於在JWT令牌中我們存儲了相應的用戶資訊和許可權,這時我們可以直接在資源伺服器中直接去解析對應令牌,就不用每次都去請求認證伺服器端點,加大認證伺服器的壓力,下面我們開始改造資源伺服器:
- 將上面認證伺服器中寫的TokenConfigure類拷貝一份到資源伺服器
- 在資源伺服器中屏蔽調之前的資源伺服器令牌解析服務( tokenService() )
- 注入TokenConfigure類,然後配置到ResourceServerSecurityConfigurer里
完整的配置如下:
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class DimplesResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "dimples";
private TokenStore tokenStore;
@Autowired
public DimplesResourceServerConfigurerAdapter(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID)
// .tokenServices(tokenService())
.tokenStore(tokenStore)
.stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 配置客戶端許可權scope
.antMatchers("/**").access("#oauth2.hasScope('all')")
.and().csrf().disable()
// 關閉session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
然後重啟服務,重新獲取令牌,然後訪問之前的測試介面: