【问题标题】:How to logout user in spring security stateless (jwt token)?如何在 Spring Security 无状态(jwt 令牌)中注销用户?
【发布时间】:2019-02-02 15:18:13
【问题描述】:

我在spring创建了一个微服务系统,在我的项目中我有3个前端和多个微服务,这些前端使用(并存储到cookie中)jwt令牌从我的微服务中获取资源。

我的用户登录场景: 当用户想要从前端登录时,我重定向到我的实时项目(另一个前端)用户在我的实时前端登录并重定向到前端并在查询参数中传递令牌,所以前端可以使用这个令牌来获取资源。 当用户从前端 2 登录时重定向到 live,当用户在存储的 live 令牌的 cookie 中登录并且没有获取用户名和密码时重定向到具有存在令牌的前端 2。 这是我的 sso :)。

但我无法注销用户,因为当用户注销时(从 cookie 中删除令牌)如何理解用户注销的其他前端。

我想我必须创建会话来获取用户登录状态。或者我需要集中令牌状态检查。

如何创建这个会话??

我的spring安全码是spring的默认安全码。

最后我为我的英语道歉。 ;)

我的实时项目代码 (UAA)

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends 
AuthorizationServerConfigurerAdapter {
@Value("${jwt.token.access-token-validity-seconds}")
private Integer accessTokenValiditySeconds;
@Value("${jwt.token.support-refresh-token}")
private Boolean supportRefreshToken;

private final AuthenticationManager authenticationManager;
private final ClientDetailsServiceImpl clientDetailsService;
private final AccountService userDetailsService;

public OAuth2AuthorizationServerConfig(AuthenticationManager authenticationManager,
        ClientDetailsServiceImpl clientDetailsService, AccountService userDetailsService) {
    super();
    this.authenticationManager = authenticationManager;
    this.clientDetailsService = clientDetailsService;
    this.userDetailsService = userDetailsService;
}

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

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

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));

    endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain)
            .authenticationManager(authenticationManager).userDetailsService(userDetailsService);
}

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

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
      JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory keyStoreKeyFactory = 
          new KeyStoreKeyFactory(new ClassPathResource("key.jks"), "sayar1234".toCharArray());
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("key"));

        Resource resource = new ClassPathResource("public-key.txt");
        String publicKey = null;
        try {
            publicKey = IOUtils.toString(resource.getInputStream());
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }

        converter.setVerifierKey(publicKey);

        return converter;
}

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

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

其他资源

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends 
ResourceServerConfigurerAdapter {

@Override
public void configure(final HttpSecurity http) throws Exception {
    // @formatter:off
    http.csrf().disable() // csrf
            .antMatcher("/**").authorizeRequests() // /**
            .antMatchers("/actuator/**").permitAll() // Actuator
            .antMatchers("/ws/**").permitAll() // websocket
            .anyRequest().authenticated();
    // @formatter:on
}

@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();
    Resource resource = new ClassPathResource("public-key.txt");
    String publicKey = null;
    try {
        publicKey = IOUtils.toString(resource.getInputStream());
    } catch (final IOException e) {
        throw new RuntimeException(e);
    }
    converter.setVerifierKey(publicKey);
    return converter;
}

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

【问题讨论】:

    标签: spring-security jwt token logout stateless


    【解决方案1】:

    我们正在使用 Redis 缓存/服务器来存储令牌。您可以在https://redis.io/documentation 阅读有关 Redis 的更多信息

    登录后,我们使用此令牌作为键存储用户上下文,并将用户信息作为后端的值存储。您还可以设置此令牌的过期时间。

    注销后,您需要从后端删除此令牌和相应的值。

    现在每个经过身份验证的请求都将具有此令牌,并将对其进行验证并检查此令牌是否存在于 Redis 中。

    2 种情况下会丢失令牌

    1. 用户已注销。
    2. 令牌已过期。

    在每个有效请求之后,我们都会更新到期时间。因此,只有在系统空闲特定时间的情况下,该令牌才会过期。

    这也是有益的分布式后端环境。

    【讨论】:

      猜你喜欢
      • 2019-09-24
      • 2020-10-19
      • 2016-03-22
      • 2015-08-25
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 2017-11-09
      • 2021-09-30
      相关资源
      最近更新 更多