一只小迷糊虫 2021-06-03 16:45 采纳率: 50%
浏览 205

spring security 开启会话管理,changeSessionId导致redis索引丢失

spring security 开启会话管理,使用redis共享session,开启防御固话攻击后,redis索引和sessions中的sessionId不一致,导致session并发不起作用

也无法获取到用户的所有会话

sessionRegistry.getAllSessions(SecurityContextHolder.getContext().getAuthentication().getPrincipal())

配置:

RedisSessionConfig

    public RedisSessionConfig(ObjectProvider<RedisConnectionFactory> redisConnectionFactory) {
       this.redisConnectionFactory = redisConnectionFactory.getIfAvailable();
    }

    @Bean
    public RedisOperations<Object, Object> sessionRedisOperations() {
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        RedisTemplate<Object, Object> objectRedisTemplate = new RedisTemplate<>();
        objectRedisTemplate.setConnectionFactory(this.redisConnectionFactory);
        objectRedisTemplate.setKeySerializer(stringRedisSerializer);
        objectRedisTemplate.setHashKeySerializer(stringRedisSerializer);
        objectRedisTemplate.afterPropertiesSet();
        this.redisTemplate = objectRedisTemplate;
        return this.redisTemplate;
    }
    @Bean("redisSessionRepository")
    public FindByIndexNameSessionRepository redisSessionRepository(RedisOperations<Object, Object> sessionRedisOperations) {
        RedisIndexedSessionRepository redisIndexedSessionRepository = new RedisIndexedSessionRepository(sessionRedisOperations);
        this.sessionRepository = redisIndexedSessionRepository;
        return redisIndexedSessionRepository;
    }
    @Bean
    @DependsOn("redisSessionRepository")
    public SpringSessionBackedSessionRegistry sessionRegistry() {
        return new SpringSessionBackedSessionRegistry(sessionRepository);
    }
WebSecurityConfigurerAdapter:

@Autowired
private SpringSessionBackedSessionRegistry sessionRegistry;

http.sessionManagement()
    .maximumSessions(1)//限定一个
    .maxSessionsPreventsLogin(false)//踢除前一个用户会话
    .sessionRegistry(sessionRegistry)
 

调试断点:

防御固话攻击 使用 changeSessionId(用户身份验证后不会创建新会话,但会更改会话 ID。)

使用 FindByIndexNameSessionRepository 操作session,存储到redis

当sessionId变化时调用RedisSession.save()

        private void save() {
            this.saveChangeSessionId();
            this.saveDelta();
        }

        private void saveDelta() {
            if (!this.delta.isEmpty()) {
                String sessionId = this.getId();
                RedisIndexedSessionRepository.this.getSessionBoundHashOperations(sessionId).putAll(this.delta);
                String principalSessionKey = RedisIndexedSessionRepository.getSessionAttrNameKey(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
                String securityPrincipalSessionKey = RedisIndexedSessionRepository.getSessionAttrNameKey("SPRING_SECURITY_CONTEXT");
                if (this.delta.containsKey(principalSessionKey) || this.delta.containsKey(securityPrincipalSessionKey)) {
                    if (this.originalPrincipalName != null) {
                        String originalPrincipalRedisKey = RedisIndexedSessionRepository.this.getPrincipalKey(this.originalPrincipalName);
                        RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey).remove(new Object[]{sessionId});
                    }

                    Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this);
                    String principal = (String)indexes.get(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
                    this.originalPrincipalName = principal;
                    if (principal != null) {
                        String principalRedisKey = RedisIndexedSessionRepository.this.getPrincipalKey(principal);
                        RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(principalRedisKey).add(new Object[]{sessionId});
                    }
                }

                this.delta = new HashMap(this.delta.size());
                Long originalExpiration = this.originalLastAccessTime != null ? this.originalLastAccessTime.plus(this.getMaxInactiveInterval()).toEpochMilli() : null;
                RedisIndexedSessionRepository.this.expirationPolicy.onExpirationUpdated(originalExpiration, this);
            }
        }

这里就会出现问题,只更新了sessions里面的 ,没有更新索引,会话管理又是根据索引找session,所以导致会话管理不起效

问题找到了,但是没有找到解决办法,各位有什么解决办法吗?万分感谢 

 

 

2021年6月4日 补充:

放到测试环境,会话管理就正常了。

本地调试就是不起作用。

 

 

 

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2022-09-07 17:52
    关注
    不知道你这个问题是否已经解决, 如果还没有解决的话:

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 以帮助更多的人 ^-^
    评论

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测