【发布时间】:2018-12-14 05:07:34
【问题描述】:
我想将我的 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")));
这是一个错误还是我错过了 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 运行项目时的行为
转到第一个端点:http://localhost:8080/hello
Redis 中的会话状态:
我们注意到会话 ID 以 7546ff 开头,会话数据包含“test”属性以及默认会话信息(创建/上次访问时间等)。
- 转到第二个端点:http://localhost:8080/invalidate
当前会话失效,并在“/hello”上执行重定向,其中test属性被添加到新的Web会话中。
- Redis 中新会话的状态:
我们注意到以 ba7de 开头的新会话 ID,新会话数据仍包含测试属性和默认会话信息。
现在,让我们用 Spring Boot 2.0.3 在同一个项目上重现这个场景。
使用 Spring Boot 2.0.3 运行项目时的行为
转到第一个端点:http://localhost:8080/hello
Redis 中的会话状态:
我们注意到会话 ID 以 12d61 开头,会话数据包含“test”属性以及默认会话信息(创建/上次访问时间等)。
转到第二个端点:http://localhost:8080/invalidate
Redis 中新会话的状态:
我们注意到这里仍然使用相同的会话 ID,但会话已从其默认信息(创建日期等)中清除。因此,当再次调用它时,会在我在原始帖子中提到的位置的 apply() 方法中的反应式 redis 会话存储库中触发 NPE:
希望这个示例项目有助于找出我这边的错误或实现问题。
【问题讨论】:
-
您能否分享一段代码,显示您在何处/在何种情况下使会话无效并解释您要实现的目标?
-
我基本上想注销一个用户(不涉及 Spring Security,因为我的登录功能只是应用页面内容自定义)。我有一个注销端点,它使会话无效 (webSession.invalidate().subscribe()) 并在主页上执行重定向,但是当再次调用会话时,它仍然是返回的旧的和无效的。我在原始帖子中提供了一个示例项目 (github.com/adsanche/test-redis-session) 和一个场景来说明我的问题。
标签: java spring spring-boot spring-webflux spring-session