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