Spring安全JWT刷新令牌未到期

时间:2018-02-25 14:36:02

标签: java spring spring-boot jwt refresh-token

我是Spring的新手,我正在使用Spring安全性处理spring boot REST,目前我实现了JWT令牌。我有一些问题,但似乎无法找到答案。我尝试添加刷新令牌 起初我以为我会将它与用户一起存储在数据库中,但Spring安全会自动完成所有操作,而我似乎无法找到如何将它存储在表用户的给定字段中。
所以,继续我决定我会尝试坚持弹簧安全自动化,并设置刷新令牌到期时间为10秒,以测试它是否到期,但遗憾的是它不能按预期工作 - 我可以使用刷新令牌,只要我想用它生成新的标记。
所以这里有几个问题:
1.如何在给定时间后使刷新令牌过期?这是我的安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Value("${security.signing-key}")
private String signingKey;

@Value("${security.encoding-strength}")
private Integer encodingStrength;

@Value("${security.security-realm}")
private String securityRealm;

@Autowired
private UserDetailsService userDetailsService;

@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
    return super.authenticationManager();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

@Bean
public PasswordEncoder passwordEncoder() {
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    return encoder;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().httpBasic()
            .realmName(securityRealm).and().csrf().disable();

}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey(signingKey);
    return converter;
}

@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
}

@Bean
@Primary
public DefaultTokenServices tokenServices() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    defaultTokenServices.setRefreshTokenValiditySeconds(10);
    return defaultTokenServices;
}

}

  1. 是否可以将刷新令牌传递给数据库并手动检查令牌是否有效,因为这是我的第一个想法。

1 个答案:

答案 0 :(得分:1)

我确实找到了答案,只是忘了更新票证。因此,默认情况下,JwtTokenStore不支持刷新令牌。 Here's JwtTokenStore source code。 因此,这意味着在设置中启用令牌实际上不会使其起作用。我所做的就是创建自己的JWT令牌存储,该存储扩展了JwtTokenStore并编写了自己的刷新令牌逻辑。

public class MyJwtTokenStore extends JwtTokenStore {

@Autowired
UserRepository userRepository;

public MyJwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {
    super(jwtTokenEnhancer);
}

@Override
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
    String username = authentication.getUserAuthentication().getName();
    User user = userRepository.findByEmail(username);
    user.setToken(refreshToken.getValue());
    userRepository.save(user);
}

@Override
public OAuth2RefreshToken readRefreshToken(String token) {
    OAuth2Authentication authentication = super.readAuthentication(token);
    String username = authentication.getUserAuthentication().getName();
    User user = userRepository.findByEmail(username);
    if (!token.equals(user.getToken())) {
        return null;
    }
    OAuth2RefreshToken refreshToken = new DefaultOAuth2RefreshToken(token);
    return refreshToken;
}

@Override
public void removeRefreshToken(OAuth2RefreshToken token) {
    OAuth2Authentication authentication = super.readAuthentication(token.getValue());
    String username = authentication.getUserAuthentication().getName();
    User user = userRepository.findByEmail(username);
    user.setToken(null);
    userRepository.save(user);
}

}

此后,我刚刚更新了我的TokenStore Bean

@Bean
public TokenStore tokenStore() {
    MyJwtTokenStore jwtTokenStore = new MyJwtTokenStore(accessTokenConverter());
    return jwtTokenStore;
    // return new JwtTokenStore(accessTokenConverter());
}

最后,我将其余设置添加到AuthorizationServerConfigurerAdapter类中,以支持刷新令牌并为其提供有效时间。

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${security.jwt.client-id}")
private String clientId;

@Value("${security.jwt.client-secret}")
private String clientSecret;

@Value("${security.jwt.grant-type}")
private String grantType;

@Value("${security.jwt.grant-type-other}")
private String grantTypeRefresh;

@Value("${security.jwt.scope-read}")
private String scopeRead;

@Value("${security.jwt.scope-write}")
private String scopeWrite = "write";

@Value("${security.jwt.resource-ids}")
private String resourceIds;

@Autowired
private TokenStore tokenStore;

@Autowired
private JwtAccessTokenConverter accessTokenConverter;

@Autowired
private AuthenticationManager authenticationManager;

@Autowired
private AppUserDetailsService userDetailsService;

@Autowired
private PasswordEncoder passwordEncoder;


@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
    configurer.inMemory()
            .withClient(clientId)
            .secret(passwordEncoder.encode(clientSecret))
            .authorizedGrantTypes(grantType, grantTypeRefresh).scopes(scopeRead, scopeWrite)
            .resourceIds(resourceIds).autoApprove(false).accessTokenValiditySeconds(1800) // 30min
            .refreshTokenValiditySeconds(86400); //24 hours
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
    enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
    endpoints.tokenStore(tokenStore).accessTokenConverter(accessTokenConverter).tokenEnhancer(enhancerChain)
            .reuseRefreshTokens(false).authenticationManager(authenticationManager)
            .userDetailsService(userDetailsService);
}

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*"); // http://localhost:4200
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

}