Spring Boot 和 Redis 中的并发会话不起作用

问题描述 投票:0回答:0

我在限制每个用户的最大并发会话数方面遇到问题。我尝试了在这里和其他网站上找到的一些解决方案,但仍然没有成功。我最终得到了这样的结果:

登录控制器

@RestController
public class LoginController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private SecurityContextRepository contextRepository;

    private SecurityContextHolderStrategy contextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();


    @PostMapping(value = "/auth/signIn", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> signIn(@RequestBody LoginForm loginForm, HttpServletRequest request, HttpServletResponse response) {
        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginForm.getUsername(), loginForm.getPassword()));
        SecurityContext context = contextHolderStrategy.createEmptyContext();
        context.setAuthentication(authentication);
        contextHolderStrategy.setContext(context);
        contextRepository.saveContext(context, request, response);

        return new ResponseEntity<>("test", HttpStatus.OK);
    }

会话配置

 @Configuration
    @EnableRedisHttpSession
    public class SessionConfig {
        @Bean
        public LettuceConnectionFactory redisConnectionFactory(){
            return new LettuceConnectionFactory();
        }
    
        @Bean
        public HttpSessionEventPublisher httpSessionEventPublisher() {
            return new HttpSessionEventPublisher();
        }
    
        @Bean
        public RedisOperations<String, Object> sessionRedisOperations(){
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory());
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            return redisTemplate;
        }
    
        @Bean
        public FindByIndexNameSessionRepository redisSessionRepository(RedisOperations<String, Object> sessionRedisOperations) {
            return new RedisIndexedSessionRepository(sessionRedisOperations);
        }
    
        public class SessionInitializer extends AbstractHttpSessionApplicationInitializer {
            public SessionInitializer(){
                super(SessionConfig.class);
            }
        }
    
        public class SecurityWebInitializer extends AbstractSecurityWebApplicationInitializer {
            @Override
            protected boolean enableHttpSessionEventPublisher() {
                return true;
            }
        }
    }

安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private FindByIndexNameSessionRepository sessionRepository;

    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
    }
    @Bean
    public SecurityContextRepository securityContextRepository(){
        return new HttpSessionSecurityContextRepository();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeHttpRequests()
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated().and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true)
                .expiredUrl("/expired")
               .sessionRegistry(sessionRegistry());

        return http.build();
    }
}

我还在我的 UserDetail 实现中实现了 hashcode 和 equals 方法,因为我发现这也可能导致问题。 当我使用 Postman 登录时,删除会话 cookie 并再次登录,Spring 继续在 Redis 中创建另一个会话。你能发现我做错了什么吗?

spring-boot spring-security redis spring-session
© www.soinside.com 2019 - 2024. All rights reserved.