我使用spring-web(4.1.7)和spring-security-oauth2(2.0.12)以及hazelcast(3.3)。
在测试此用户(没有会话)时,访问该站点并单击该链接以启动OpenId Connect登录。
我添加了一个HttpSessionListener来检查会话的创建时间。
OAuth2RestTemplate用于执行身份验证并包含以下行: OAuth2AccessToken accessToken = context.getAccessToken();
上下文对象是具有会话范围的OAuth2ClientContext bean,似乎使用此对象(不实例化它)会触发会话的创建(并且上下文存储在会话中)。
到目前为止一直很好,但我遇到的问题是我使用Hazelcast进行会话复制,并且没有创建Hazelcast会话。这是一个问题,因为当请求完成并且没有找到HttpSession的Hazelcast会话时,Hazelcast过滤器将破坏HttpSession。
我的问题是,如何触发创建Hazelcast过滤器? 用于创建会话的堆栈跟踪显示我们不会调用Hazelcast来创建会话:
WebSessionListener.sessionCreated(HttpSessionEvent) line: 15
StandardSession.tellNew() line: 367
StandardSession.setId(String) line: 341
StandardManager(ManagerBase).createSession(String) line: 857
StandardManager.createSession(String) line: 291
Request.doGetSession(boolean) line: 2606
Request.getSession(boolean) line: 2316
RequestFacade.getSession(boolean) line: 841
ServletRequestAttributes.getSession(boolean) line: 111
ServletRequestAttributes.getSessionMutex() line: 244
SessionScope.get(String, ObjectFactory<?>) line: 91
DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class<T>, Object[], boolean) line: 337
DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 194
SimpleBeanTargetSource.getTarget() line: 35
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 187
$Proxy322.getAccessToken() line: not available
OAuth2RestTemplate.getAccessToken() line: 169
我有一些黑客攻击,发现如果我打电话给 request.getSession(真); 这将创建两者
堆栈跟踪显示我们在创建HttpSession之前通过Hazelcast方法SpringAwareWebFilter.createNewSession。
所以我的问题似乎是:
使用RequestWrapper(HttpServletRequestWrapper)时.getSession() 获得/创建一个会话,这是Hazelcast意识到的。
但是,当spring尝试创建会话时(使用会话范围bean时触发),它不会识别Hazelcast。
这是预期的行为,即spring不知道创建Hazelcast会话,我必须找到一些解决方法吗?或者任何人都可以推荐任何进一步调试方法吗?
在web.xml中,hazelcast配置为:
<filter>
<filter-name>hazelcast-filter</filter-name>
<filter-class>com.hazelcast.web.spring.SpringAwareWebFilter</filter-class>
<init-param>
<param-name>map-name</param-name>
<param-value>sessions</param-value>
</init-param>
<init-param>
<param-name>sticky-session</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cookie-name</param-name>
<param-value>hazelcast.session</param-value>
</init-param>
<init-param>
<param-name>cookie-secure</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cookie-http-only</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>config-location</param-name>
<param-value>hazelcast-geneva.xml</param-value>
</init-param>
<init-param>
<param-name>shutdown-on-destroy</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hazelcast-filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
作为参考,如果我强制调用request.getSession并且此调用通过Hazelcast过滤器WebFilter和SpringAwareWebFilter,则堆栈链是这样的(与上面缺少Hazelcast过滤器的堆栈相比)
WebSessionListener.sessionCreated(HttpSessionEvent) line: 15
StandardSession.tellNew() line: 367
StandardSession.setId(String) line: 341
StandardManager(ManagerBase).createSession(String) line: 857
StandardManager.createSession(String) line: 291
Request.doGetSession(boolean) line: 2606
Request.getSession(boolean) line: 2316
RequestFacade.getSession(boolean) line: 841
WebFilter$RequestWrapper(HttpServletRequestWrapper).getSession(boolean) line: 255
WebFilter$RequestWrapper.getOriginalSession(boolean) line: 533
SpringAwareWebFilter(WebFilter).createNewSession(WebFilter$RequestWrapper, String) line: 307
SpringAwareWebFilter.createNewSession(WebFilter$RequestWrapper, String) line: 47
WebFilter$RequestWrapper.getSession(boolean) line: 605
WebFilter$RequestWrapper.getSession(boolean) line: 515
RequestWrapper(HttpServletRequestWrapper).getSession(boolean) line: 255
我发现在我的会话范围bean上调用一个方法时,它会触发对ServletRequestAttributes.getSession(boolean)的调用。
此对象有一个名为request的属性,它调用getSession(boolean)。 如果这个请求对象是由Hazelcast过滤器创建的WebFilter $ RequestWrapper,我怀疑一切都会正常工作。
然而,在调用Hazelcast过滤器doFilter之前,ServletRequestAttributes使用HttpServletRequest初始化(未被Hazelcast包装)。
似乎无法更新ServletRequestAttributes中的请求属性,但也许有一些方法可以创建一个新属性。
我正在使用RequestContextListener,它在任何过滤器之前被触发,并在Hazelcast过滤器有机会将其包装之前在ServletRequestAttributes中设置请求对象。我删除了RequestContextListener并将其替换为RequestContextFilter(看起来就像他们在spring boot:https://github.com/spring-projects/spring-boot/issues/2637中所做的那样)。这可以确保在初始化ServletRequestAttributes时,它会获取Hazelcast请求对象。
答案 0 :(得分:3)
Hazelcast WebFilter
(以及SpringAwareFilter
)将请求包装在RequestWrapper
中。调用request.getSession()
时,包装器会创建一个新的HazelcastSession
,或者返回现有的WebFilter
。
这就是为什么ServletRequestListener
需要在其他过滤器之前定义的原因。来自hazelcast-wm's README:
确保将Hazelcast过滤器放在所有其他过滤器之前(如果有的话);你可以把它放在最顶层。
Servlet容器在过滤器之前处理ServletRequestListener
个实例(请参阅this answer on SO)。因此,如果request.getSession()
(或任何其他代码段)在WebFilter
有机会包装请求之前调用HazelcastSession
,则不会创建WebFilter
并且会话复制赢了“工作。
确保Hazelcast request.getSession()
在对function routerConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('404', {
url: '/404',
templateUrl: '404.html'
})
.state('home', {
url: '/',
templateUrl: 'home.html'
});
$urlRouterProvider.otherwise('/404');
}
的任何调用之前解决请求。