Websession 失效在 Spring Boot 2.0.2 中不起作用

Websession invalidation not working from Spring Boot 2.0.2

我想将我的 Spring Webflux 项目从 Spring Boot 2.0.1 升级到 Spring Boot 2.0.3。在我的项目中,我的会话由 Spring Session Data Redis 支持。升级 Spring Boot 版本时,我注意到 Spring Boot 2.0.2+.

的 websession 失效问题

在 Spring Boot 2.0.1 中,我以这种方式使我的会话无效:

webSession.invalidate().subscribe();

这导致我当前的会话被销毁,并生成了一个新的会话 ID、创建时间等

然而,从 Spring Boot 2.0.2 开始,相同的代码似乎并没有完全破坏会话。当前的session信息就是"cleared",之后还是用同样的session ID。这是一个问题,因为它会导致 ReactiveRedisOperationsSessionRepository.class 中的空指针异常:

private static final class SessionMapper implements Function<Map<String, Object>, MapSession> {
        private final String id;

        private SessionMapper(String id) {
            this.id = id;
        }

        public MapSession apply(Map<String, Object> map) {
            MapSession session = new MapSession(this.id);
            session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));
            session.setLastAccessedTime(Instant.ofEpochMilli((Long)map.get("lastAccessedTime")));
            session.setMaxInactiveInterval(Duration.ofSeconds((long)(Integer)map.get("maxInactiveInterval")));
            map.forEach((name, value) -> {
                if (name.startsWith("sessionAttr:")) {
                    session.setAttribute(name.substring("sessionAttr:".length()), value);
                }

            });
            return session;
        }
    }

由于会话数据为空(没有创建时间等),以下行引发 NPE:

session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));

这是错误还是我错过了 Spring Boot 2.0.2+ 中关于 Spring 会话的新内容?

更新

为了提供更多信息,我创建了一个重现该问题的示例项目:https://github.com/adsanche/test-redis-session

此项目包含一个公开两个端点的简单控制器:

@Controller
public class HelloController {

    @GetMapping(value = "/hello")
    public String hello(final WebSession webSession) {

        webSession.getAttributes().put("test", "TEST");

        return "index";
    }

    @GetMapping(value = "/invalidate")
    public String invalidate(final WebSession webSession) {

        webSession.invalidate().subscribe();

        return UrlBasedViewResolver.REDIRECT_URL_PREFIX + "/hello";
    }
}

当 运行 项目使用 Spring Boot 2.0.1

时的行为

我们注意到会话 ID 以 7546ff 开头,会话数据包含 "test" 属性以及默认会话信息(creation/last 访问时间等)。

当前会话失效,在“/hello”上执行重定向,在新的网络会话中添加测试属性。

我们注意到新会话ID以ba7de开头,新会话数据仍然包含测试属性和默认会话信息。

现在,让我们使用 Spring Boot 2.0.3.

在同一个项目上重现这个场景

当 运行 项目使用 Spring Boot 2.0.3

时的行为

我们注意到会话 ID 以 12d61 开头,会话数据包含 "test" 属性以及默认会话信息(creation/last 访问时间等)。

我们在这里注意到,仍然使用相同的会话 ID,但会话甚至已从其默认信息(创建日期等)中清除。因此,当它再次被调用时,在我在原始 post:

希望这个示例项目有助于确定它是我这边的错误还是实施问题。

这是 Spring Session 的 SpringSessionWebSessionStore 中的错误,或者更具体地说,是其内部 WebSession 实现中的错误。问题是 WebSession#invalidate session 仅从底层 session 存储中清除,但未标记为无效,因此后续请求处理仍然使用相同的 session id .

我已打开 gh-1114 以在 Spring Session 中解决此问题。

我相信您之前没有遇到过这种情况,即 Spring Session 2.0.2.RELEASE 及以下版本由于 SpringSessionWebSessionStore 中的另一个错误已在 [=15] 中解决=] - 参见 gh-1039。这个问题是关于无法更新 lastAccessedTime,一旦我们修复了你描述的场景开始失败,因为 session 无效(和删除)session id 仅使用 lastAccessedTime属性。