Hazelcast + spring 安全性 + 分布式会话 = 如何让它工作?
Hazelcast + spring security + distributed sessions = how to make it work?
受到 http://docs.hazelcast.org/docs/latest/manual/html/websessionreplication.html 的启发,我决定尝试一下并在我的 Spring MVC + 安全应用程序中使用它。
我遇到的第一个问题是 - Hazelcast 抱怨找不到 sessionRegistry
bean。我通过将以下 bean 添加到 spring-security context
很快解决了这个问题
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
但是我马上就遇到了下一个问题,仍然无法解决。
这是发生了什么:
- 启动tomcat(假设应用程序也将启动)
- 登录网站 - 确定
- 注销 - 正常(关注:注销正常,
JSESSIONID
和 REMEMBER_ME_TOKEN
cookie 已清除,但 hazelcast.sessionId
cookie 未 清除)
- 重启tomcat
- 导航到索引页
- 错误:发生无限重定向到
invalidSessionStrategy
经过一些调试我发现了几个事实:
- 发生这种情况是因为在
SessionManagementFilter#doFilter
中检查 request.isRequestedSessionIdValid()
returns false
JSESSIONID
和 hazelcast.sessionId
不同(这是我设计的假设)
- 看起来问题是由于调用
request.isRequestedSessionIdValid()
和 request.getSession()
之间的不一致而发生的 - 看起来如果前者 returns false
,那么后者假设创建新会话 - 这不会发生
到目前为止我尝试了什么(但没有帮助):
- 使用内置 spring 安全注销处理程序手动清除
hazelcast.sessionId
cookie(没有成功,coockie 以相同的值再次出现)
- 解决方法 https://github.com/hazelcast/hazelcast/issues/3049,即在注销时发送
HttpSessionDestroyedEvent
。未发现效果
- 尝试使用
JSESSIONID
作为 hazelcast cookie 名称的会话 ID(在那种情况下我只能打开 ap 一次,所有后续请求都会导致无限重定向到 invalid-session
)
所以...显然它并不像 Hazelcast 官方文档中所说的那么简单。有什么想法可以让它发挥作用吗?
看来我找到了解决 infinite redirect to invalid session
问题的方法。我不确定这是捷径还是 100% 正确的方法...
我使用以下代码创建了自定义 InvalidSessionStrategyImpl
:
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (request.getSession(false) instanceof HazelcastHttpSession) {
HazelcastHttpSession hazelCastSession = (HazelcastHttpSession) request.getSession(false);
hazelCastSession.invalidate();
} else {
request.getSession();
}
redirectStrategy.sendRedirect(request, response, redirecctTo);
}
p.s。如果你好奇 - 在那之后我遇到了另一个问题:过度 CPU 消费。 Hazelcast 吃 100% CPU。完全不可接受的问题(尤其是对于像 Jelastic 这样的云部署,您需要按资源使用量付费)。
受到 http://docs.hazelcast.org/docs/latest/manual/html/websessionreplication.html 的启发,我决定尝试一下并在我的 Spring MVC + 安全应用程序中使用它。
我遇到的第一个问题是 - Hazelcast 抱怨找不到 sessionRegistry
bean。我通过将以下 bean 添加到 spring-security context
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
但是我马上就遇到了下一个问题,仍然无法解决。 这是发生了什么:
- 启动tomcat(假设应用程序也将启动)
- 登录网站 - 确定
- 注销 - 正常(关注:注销正常,
JSESSIONID
和REMEMBER_ME_TOKEN
cookie 已清除,但hazelcast.sessionId
cookie 未 清除) - 重启tomcat
- 导航到索引页
- 错误:发生无限重定向到
invalidSessionStrategy
经过一些调试我发现了几个事实:
- 发生这种情况是因为在
SessionManagementFilter#doFilter
中检查request.isRequestedSessionIdValid()
returnsfalse
JSESSIONID
和hazelcast.sessionId
不同(这是我设计的假设)- 看起来问题是由于调用
request.isRequestedSessionIdValid()
和request.getSession()
之间的不一致而发生的 - 看起来如果前者 returnsfalse
,那么后者假设创建新会话 - 这不会发生
到目前为止我尝试了什么(但没有帮助):
- 使用内置 spring 安全注销处理程序手动清除
hazelcast.sessionId
cookie(没有成功,coockie 以相同的值再次出现) - 解决方法 https://github.com/hazelcast/hazelcast/issues/3049,即在注销时发送
HttpSessionDestroyedEvent
。未发现效果 - 尝试使用
JSESSIONID
作为 hazelcast cookie 名称的会话 ID(在那种情况下我只能打开 ap 一次,所有后续请求都会导致无限重定向到invalid-session
)
所以...显然它并不像 Hazelcast 官方文档中所说的那么简单。有什么想法可以让它发挥作用吗?
看来我找到了解决 infinite redirect to invalid session
问题的方法。我不确定这是捷径还是 100% 正确的方法...
我使用以下代码创建了自定义 InvalidSessionStrategyImpl
:
@Override
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (request.getSession(false) instanceof HazelcastHttpSession) {
HazelcastHttpSession hazelCastSession = (HazelcastHttpSession) request.getSession(false);
hazelCastSession.invalidate();
} else {
request.getSession();
}
redirectStrategy.sendRedirect(request, response, redirecctTo);
}
p.s。如果你好奇 - 在那之后我遇到了另一个问题:过度 CPU 消费。 Hazelcast 吃 100% CPU。完全不可接受的问题(尤其是对于像 Jelastic 这样的云部署,您需要按资源使用量付费)。