2017-08-28 114 views
0

我在春天啓動的應用程序如下配置:春季安全的OAuth2撤銷令牌不工作

@Configuration 
public class SecurityConfig { 

@Configuration 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private MyUserDetailsService userDetailsService; 

    @Autowired 
    private BCryptPasswordEncoder passwordEncoder; 

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

    @Bean 
    @Override 
    public AuthenticationManager authenticationManagerBean() throws Exception { 
     return super.authenticationManagerBean(); 
    } 
} 

@Configuration 
@EnableAuthorizationServer 
public static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 

    @Autowired 
    private MyUserDetailsService userDetailsService; 

    @Autowired 
    @Qualifier("authenticationManagerBean") 
    private AuthenticationManager authenticationManager; 

    @Autowired 
    @Qualifier("myOauth2ClientDetailsService") 
    private ClientDetailsService clientDetailsService; 

    @Override 
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
     clients.withClientDetails(clientDetailsService); 
    } 

    @Override 
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
     // set custom exception translator 
     endpoints.exceptionTranslator(e -> { 
      if (e instanceof OAuth2Exception) { 
       OAuth2Exception exception = (OAuth2Exception) e; 
       return ResponseEntity 
         .status(exception.getHttpErrorCode()) 
         .body(new MyWLoginException(exception.getMessage())); 
      } else { 
       throw e; 
      } 
     }); 
     // other settings 
     TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); 
     tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter())); 
     endpoints.authenticationManager(authenticationManager).userDetailsService(userDetailsService).tokenStore(tokenStore()) 
       .tokenEnhancer(tokenEnhancerChain); 
    } 

    @Override 
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { 
     security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); 
    } 

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

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

    @Bean 
    public TokenEnhancer tokenEnhancer() { 
     return new MyTokenEnhancer(); 
    } 

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

@Configuration 
@EnableResourceServer 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
@Order(-10) 
public static class ResourceServerConfig extends ResourceServerConfigurerAdapter { 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 
     http.addFilterAfter(new AuditorFilter(), BasicAuthenticationFilter.class) 
       .headers().frameOptions().disable() 
      .and().csrf().disable() 
      .authorizeRequests() 
       .antMatchers("/img/**").permitAll() 
       .anyRequest().authenticated(); 

    } 

    @Override 
    public void configure(ResourceServerSecurityConfigurer config) { 
     config.tokenServices(tokenServices()); 
    } 

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

    @Bean 
    public JwtAccessTokenConverter accessTokenConverter() { 
     JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
     DefaultAccessTokenConverter defaultAccessTokenConverter = new DefaultAccessTokenConverter(); 
     defaultAccessTokenConverter.setUserTokenConverter(userAuthenticationConverter()); 
     converter.setAccessTokenConverter(defaultAccessTokenConverter); 
     converter.setSigningKey("123"); 
     return converter; 
    } 

    @Bean 
    public UserAuthenticationConverter userAuthenticationConverter() { 
     return new MyUserAuthenticationConverter(); 
    } 

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

}

另外,我有特殊的端點撤銷令牌,它可以處理在下面的方法要求:

@Autowired 
private TokenStore tokenStore; 
@Autowired 
private AuthorizationServerTokenServices authorizationServerTokenServices; 
@Autowired 
private ResourceServerTokenServices resourceServerTokenServices; 
... 
final String tokenValue = ((OAuth2AuthenticationDetails) SecurityContextHolder.getContext().getAuthentication().getDetails()).getTokenValue(); 
     final OAuth2AccessToken token = tokenStore.readAccessToken(tokenValue); 
     tokenStore.removeAccessToken(token); 
     boolean authRemoved = ((DefaultTokenServices) authorizationServerTokenServices).revokeToken(tokenValue); // <- true 
     boolean resourceRemoved = ((DefaultTokenServices) resourceServerTokenServices).revokeToken(tokenValue); // <- true 
     SecurityContextHolder.getContext().setAuthentication(null); 

沒有任何錯誤。我看到令牌服務返回true(已刪除)。但是,當我使用舊訪問令牌調用任何端點時,它的作用就像這個令牌仍然存在。但是我從auth服務器和資源服務器中刪除了令牌。如何解決這個問題?

回答

1

令牌撤銷不會使用JWT,因爲它嵌入令牌到期。頒發後,授權服務器將不會捕獲有關令牌的任何信息。所以,也許你應該嘗試在你的授權服務器中使用JdbcTokenStore來將你的令牌保存在一個數據庫中,然後根據需要撤銷它們(或者也可能在內存中)。如果你的應用程序是分開的,你可以使用RemoteTokenServices來驗證你的令牌。

Here是一個教程,告訴你如何做到這一點。

+0

我想你是對的。我打算使用RedisTokenStore。我認爲我需要單一和清晰的存儲器來存儲令牌 –