Spring Security OAuth2 撤销令牌不起作用
Posted
技术标签:
【中文标题】Spring Security OAuth2 撤销令牌不起作用【英文标题】:Spring Security OAuth2 revoke token does not work 【发布时间】:2018-02-05 15:51:11 【问题描述】:我的 Spring Boot 应用中有以下配置:
@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
(已删除)。但是当我用旧的访问令牌调用任何端点时,它就像这个令牌仍然存在一样工作。但是我从身份验证服务器和资源服务器中删除了令牌。如何解决这个问题?
【问题讨论】:
【参考方案1】:令牌撤销无法使用 JWT 进行,因为它嵌入其中的令牌已过期。您的授权服务器在颁发后不会捕获有关令牌的任何信息。因此,也许您应该尝试在您的授权服务器中使用JdbcTokenStore 将您的令牌保存在数据库中,然后根据需要撤销它们(或者也可以在内存中)。如果您的应用是分开的,您可以使用RemoteTokenServices 来验证您的令牌。
Here 是一个向您展示如何完成此任务的教程。
【讨论】:
我猜你是对的。我打算使用 RedisTokenStore。我认为我需要单一且清晰的令牌存储以上是关于Spring Security OAuth2 撤销令牌不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security Oauth2 removeAccessToken 不起作用
Spring Security 入门(1-3)Spring Security oauth2.0 指南
Spring-Security OAuth2 设置 - 无法找到 oauth2 命名空间处理程序
Spring Security OAuth2 v5:NoSuchBeanDefinitionException:'org.springframework.security.oauth2.jwt.Jwt