首页 文章

spring-boot redis:如何使用户的所有会话无效?

提问于
浏览
13

我是redis的新手 . 我已经按照本教程使用了redis的HttpSession .

https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot.html

现在我的应用程序已“退出所有设备”选项 . 单击该按钮时,如何删除或使该用户的所有会话无效?

此外,当用户更改其密码时,如何使除当前会话之外的所有会话无效?

Edit:

我尝试使用Session Registry .

@Autowired
private FindByIndexNameSessionRepository sessionRepository;

@Autowired
FindByIndexNameSessionRepository<? extends ExpiringSession> sessions;

@RequestMapping(value = "/logoutalldevices", method = RequestMethod.GET)
public Response test(HttpServletRequest request, HttpServletResponse response) throws Exception {

    SpringSessionBackedSessionRegistry sessionRegistry = new SpringSessionBackedSessionRegistry(sessionRepository);

    Collection<? extends ExpiringSession> usersSessions = sessions
            .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "myUserId")
            .values();

    usersSessions.forEach((temp) -> {
        String sessionId = temp.getId();
        // sessionRegistry.removeSessionInformation(sessionId);
        SessionInformation info = sessionRegistry.getSessionInformation(sessionId);
        info.expireNow();
    });

    return Response.ok().build();
}

但它不会从redis db中删除会话或使其无效 . 虽然它在名为'sessionAttr:org.springframework.session.security.SpringSessionBackedSessionInformation.EXPIRED'的会话中添加了一个新属性,其值为true . 我可以使用redis客户端在redis db中看到这个新的键值对

HGETALL 'sessionid'

Edit

我尝试使用redistemplate从redis db手动删除会话 .

@Autowired
RedisTemplate<String, String> redisTemplate;

---------

redisTemplate.delete("spring:session:sessions:" + sessionId);
redisTemplate.delete("spring:session:sessions:expires:" + sessionId);

这几乎可行 . 它从redis db中删除值,但不删除密钥 .

127.0.0.1:6379> keys *
1) "spring:session:sessions:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"
2) "spring:session:sessions:expires:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"
3) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:1"
127.0.0.1:6379> hgetall spring:session:sessions:25635a14-a4f1-4aa1-bf5a-bc20f972eec7
1) "lastAccessedTime"
2) "\xac\xed\x00\x05sr\x00\x0ejava.lang.Long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01J\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01[R'\x15\xc1"
127.0.0.1:6379>

除了lastAccessedTime时,它删除了会话中的所有其他键值对 .

还有一个奇怪的是,这是我在执行 redisTemplate.delete("key") 时在redis监视器中看到的日志:

1491731944.899711 [0 127.0.0.1:62816] "DEL" "spring:session:sessions:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"
1491731944.899853 [0 127.0.0.1:62816] "DEL" "spring:session:sessions:expires:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"

如果我将上述两个命令复制并粘贴到redis-client并执行,则删除密钥 . 当我执行 keys * 时,我看不到键 . 我想知道为什么在使用 RedisTemplate 删除密钥时不会删除密钥

127.0.0.1:6379> "DEL" "spring:session:sessions:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"
(integer) 1
127.0.0.1:6379> "DEL" "spring:session:sessions:expires:25635a14-a4f1-4aa1-bf5a-bc20f972eec7"
(integer) 1
127.0.0.1:6379> keys *
1) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:1"
127.0.0.1:6379>

3 回答

  • 0

    我想知道 you are following the correct path 用于使用户会话无效

    usersSessions.forEach((session) -> {        
            sessionRegistry.getSessionInformation(session.getId()).expireNow();
        });
    

    有些事要注意

    SessionInformation.expireNow()
    

    并不意味着从 redis 数据库中删除条目,它只是将您过期的属性附加到会话中,正如您正确提到的那样 .

    But how this invalidates the session of the user?

    这里是ConcurrentSessionFilter进入游戏 .doFilter() 方法的诀窍 automatically logging out

    这是 ConcurrentSessionFilter 的片段

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
    
        HttpSession session = request.getSession(false);
    
        if (session != null) {
            SessionInformation info = sessionRegistry.getSessionInformation(session
                    .getId());
    
            if (info != null) {
                if (info.isExpired()) {
                    // Expired - abort processing
                    doLogout(request, response);
    
                    String targetUrl = determineExpiredUrl(request, info);
    
                    if (targetUrl != null) {
                        redirectStrategy.sendRedirect(request, response, targetUrl);
    
                        return;
                    }
                    else {
                        response.getWriter().print(
                                "This session has been expired (possibly due to multiple concurrent "
                                        + "logins being attempted as the same user).");
                        response.flushBuffer();
                    }
    
                    return;
                }
                else {
                    // Non-expired - update last request date/time
                    sessionRegistry.refreshLastRequest(info.getSessionId());
                }
            }
        }
    
        chain.doFilter(request, response);
    }
    

    干杯!

  • 5

    尝试使用删除键“redisTemplate.opsForValue() . getOperations() . delete(KEY);”

  • 0

    试试这个

    usersSessions.forEach((session) -> {        
            sessionRegistry.delete(session.getId());
      });
    

相关问题