OAuth + Security – 3 – JWT令牌

為什麼使用JWT令牌

在上面的資源伺服器中,通過配置,我們了解到,當我們拿著token去獲取資源時,程式會先去調用遠程認證伺服器的端點去驗證解析token,或者在本地解析校驗token,這樣毫無疑問,當訪問量過大的時候,對認證伺服器的壓力可想而知,所以為了解決上面的問題,我們採用JWT令牌格式,可以優化上面的問題。

令牌採用JWT格式即可解決上邊的問題,用戶認證通過會得到一個JWT令牌,JWT令牌中已經包括了用戶相關的資訊,客戶端只需要攜帶JWT訪問資源服務,資源服務根據事先約定的演算法自行完成令牌校驗,無需每次都請求認證服務完成授權。

改造認證伺服器

  1. 修改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;
    }


}
  1. 修改認證伺服器的配置
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;
    }
  1. 最後別忘了在pom中添加JWT的依賴,否則項目將會報錯
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-jwt</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>

測試結果如下:

image

可以使用OAuth的/oauth/check_token端點來解析驗證一下該token

image

改造資源伺服器

當我們使用了JWT令牌以後,由於在JWT令牌中我們存儲了相應的用戶資訊和許可權,這時我們可以直接在資源伺服器中直接去解析對應令牌,就不用每次都去請求認證伺服器端點,加大認證伺服器的壓力,下面我們開始改造資源伺服器:

  1. 將上面認證伺服器中寫的TokenConfigure類拷貝一份到資源伺服器
  2. 在資源伺服器中屏蔽調之前的資源伺服器令牌解析服務( tokenService() )
  3. 注入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);
    }

}

然後重啟服務,重新獲取令牌,然後訪問之前的測試介面:

image