【问题标题】:Spring security JWT refresh token not expiringSpring Security JWT 刷新令牌不会过期
【发布时间】:2018-08-05 02:11:42
【问题描述】:

我是 Spring 新手,我正在使用 Spring Security 开发 Spring Boot REST,目前我实现了 JWT 令牌。我有一些问题,但似乎无法找到答案。我尝试添加刷新令牌。
起初我以为我会将它与用户一起存储在数据库中,但 Spring Security 会自动完成所有操作,我似乎无法找到如何将它存储在表用户的给定字段中。
因此,继续前进,我决定尝试坚持使用 Spring Security 自动化,并将刷新令牌过期时间设置为 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. 是否可以将刷新令牌传递给数据库并手动检查令牌是否有效,因为这是我的第一个想法。

【问题讨论】:

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


    【解决方案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;
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-04
      • 2017-11-09
      • 2016-03-22
      • 2017-10-27
      • 2018-07-22
      • 2017-12-02
      • 2016-09-04
      • 2018-01-28
      相关资源
      最近更新 更多