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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43090679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 07:04:18  来源:igfitidea点击:

spring-boot redis : How to invalidate all sessions of a user?

javaspringsessionredis

提问by Sarath Nagesh

I'm new to redis. I've followed this tutorial to use HttpSession with redis.

我是 redis 的新手。我已经按照本教程将 HttpSession 与 redis 一起使用。

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

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

Now my application has 'Sign out from all devices' option. When that is clicked how do I remove or invalidate all sessions of that user?

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

Also when the user changes his password, how do I invalidate all his sessions except the current session?

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

Edit:

编辑:

I tried using 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();
}

But it is not removing the session from redis db or invalidating it. though it's adding a new attribute to the session named 'sessionAttr:org.springframework.session.security.SpringSessionBackedSessionInformation.EXPIRED' with value true. I can see this new key value pair in redis db using redis client when I do

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

HGETALL 'sessionid'

HGETALL 'sessionid'

Edit

编辑

I tried deleting the session manually from redis db using redistemplate.

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

@Autowired
RedisTemplate<String, String> redisTemplate;

---------

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

This almost works. It deletes the value from redis db, but not the key.

这几乎有效。它从 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> 

It deleted all other key values pairs inside the session except lastAccessedTime time.

它删除了会话中除 lastAccessedTime 时间之外的所有其他键值对。

Also one weird this is, this is the log I see in redis monitor when redisTemplate.delete("key")is executed:

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

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"

If I copy and paste the above two commands to redis-client and execute, the keys are deleted. I do not see keys when I execute keys *anymore. I wonder why the key is not getting deleted when its deleted using RedisTemplate

如果我把上面两个命令复制粘贴到redis-client执行,key就被删除了。当我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>

采纳答案by Mr.Arjun

I would like to know you that you are following the correct pathfor invalidating the user sessions

我想知道您是you are following the correct path为了使用户会话无效

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

Somethings to note

注意事项

SessionInformation.expireNow()

is not mean to remove entries from the redisdatabase, it just appends the expired attribute to session as you rightly mentioned.

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

But how this invalidates the session of the user?

但这如何使用户的会话无效?

Here comes the ConcurrentSessionFilterinto play where .doFilter()method does the trick of automatically logging out

这是ConcurrentSessionFilter发挥作用的地方, .doFilter()方法是automatically logging out

Here is the snippet for ConcurrentSessionFilter

这是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);
}

Cheers to that!

为此干杯!

回答by Sagar U

Try this

试试这个

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

回答by ozooxo

If you just want to do one time thing in debugging process, you can just log into redis_cliand flush all Redis keys.

如果你只想在调试过程中做一次事情,你可以登录redis_cli并刷新所有 Redis 键。

$ redis-cli
127.0.0.1:6379> KEYS *
1) "spring:session:index:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:bbb"
2) "spring:session:expirations:1558782600000"
3) "spring:session:expirations:1558783140000"
4) "spring:session:sessions:expires:953146bf-7300-4394-bbf0-bf606ff6b326"
5) "spring:session:expirations:1558782540000"
6) "spring:session:sessions:953146bf-7300-4394-bbf0-bf606ff6b326"
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379>

回答by Radhey Shyam

Try this for delete key "redisTemplate.opsForValue().getOperations().delete(KEY);"

试试这个删除键“redisTemplate.opsForValue().getOperations().delete(KEY);”