从Spring Boot 2.0.2起,Websession失效不起作用

时间:2018-07-05 16:20:04

标签: java spring spring-boot spring-webflux spring-session

我想将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开始,相同的代码似乎并没有完全破坏会话。当前会话信息只是被“清除”,并且之后仍使用相同的会话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")));

是Bug还是我错过了Spring Boot 2.0.2+中有关Spring Session的新东西?

更新

为了提供更多信息,我创建了一个示例项目来重现该问题: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运行项目时的行为

Sess

我们注意到会话ID以7546ff开头,并且会话数据包含“ test”属性以及默认会话信息(创建/上次访问时间等)。

当前会话无效,并且在“ / hello”上执行重定向,在该重定向中,将test属性添加到新的Web会话中。

  • Redis中新会话的状态:

enter image description here

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

现在,让我们在与Spring Boot 2.0.3相同的项目上重现此场景。

使用Spring Boot 2.0.3运行项目时的行为

enter image description here

我们注意到以12d61开头的会话ID,以及包含“测试”属性和默认会话信息(创建/上次访问时间等)的会话数据。

enter image description here

我们在这里注意到仍然使用相同的会话ID,但是即使从其默认信息(创建日期等)中也清除了该会话。因此,当再次调用它时,在我在原始帖子中提到的位置的 apply()方法中的反应式redis会话存储库中会触发NPE:

enter image description here

希望这个示例项目可以帮助我确定这是错误还是实现方面的问题。

1 个答案:

答案 0 :(得分:1)

这是Spring Session SpringSessionWebSessionStore,或更具体地说是其内部WebSession实现中的错误。问题在于,WebSession#invalidate会话仅从基础会话存储中清除,而没有标记为无效,因此后续请求处理仍使用相同的会话ID结束。

我已经开放gh-1114来在Spring Session中解决这个问题。

我相信您之前(即春季会话2.0.2.RELEASE和更低版本中没有遇到过这种情况,这是由于SpringSessionWebSessionStore中已解决的2.0.3.RELEASE中的另一个错误-请参见gh-1039。此问题与无法更新lastAccessedTime有关,一旦我们解决了您所描述的情况,由于无效(和已删除)会话ID的会话仅使用lastAccessedTime属性进行保存的问题,该方案开始失败。