gpt4 book ai didi

java - 作用域 bean 应如何在 Hazelcast 中触发 session 创建

转载 作者:行者123 更新时间:2023-12-01 21:11:29 25 4
gpt4 key购买 nike

我将 spring-web (4.1.7) 与 spring-security-oauth2 (2.0.12) 和 hazelcast (3.3) 一起使用。

在测试时,用户(没有 session )访问该站点并单击链接以启动 OpenId Connect 登录。

我添加了一个 HttpSessionListener 来检查 session 何时创建。

OAuth2RestTemplate 用于执行身份验证并包含以下行:OAuth2AccessToken accessToken = context.getAccessToken();

上下文对象是一个具有 session 范围的 OAuth2ClientContext bean,似乎使用此对象(而不是实例化它)会触发 session 的创建(并且上下文存储在 session 中)。

到目前为止一切顺利,但我遇到的问题是我使用 Hazelcast 进行 session 复制,但没有创建 Hazelcast session 。这是一个问题,因为当请求完成并且没有找到 HttpSession 的 Hazelcast session 时,Hazelcast 过滤器将销毁 HttpSession。

我的问题是,如何触发 Hazelcast 过滤器的创建?创建 session 的堆栈跟踪显示我们没有调用 Hazelcast 来创建 session :

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(true);这将创建两者

  1. HttpSession
  2. Hazelcast session

堆栈跟踪显示我们在创建 HttpSession 之前执行了 Hazelcast 方法 SpringAwareWebFilter.createNewSession。

所以我遇到的问题似乎是:

使用 RequestWrapper(HttpServletRequestWrapper).getSession() 时获取/创建 session ,这是 Hazelcast 感知的。

但是,当 spring 尝试创建 session (在使用 session 作用域 bean 时触发)时,它无法识别 Hazelcast。

这是预期的行为吗?即 spring 不知道创建 Hazelcast session ,我必须找到一些解决方法?或者有人可以推荐任何进一步的方法来调试这个吗?

在 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

更新

我发现,当在 session 作用域 bean 上调用方法时,它会触发对 ServletRequestAttributes.getSession(boolean) 的调用。

该对象有一个名为 request 的属性,在该属性上调用 getSession(boolean)。如果这个请求对象是 Hazelcast 过滤器创建的 WebFilter$RequestWrapper,我怀疑一切都会正常工作。

但是,在调用 Hazelcast 过滤器 doFilter 之前,ServletRequestAttributes 已使用 HttpServletRequest(未由 Hazelcast 包装)进行初始化。

似乎不可能更新 ServletRequestAttributes 中的请求属性,但也许有某种方法可以创建新的属性。

更新2

我使用的是 RequestContextListener,它在任何过滤器之前被触发,并在 Hazelcast 过滤器有机会包装请求对象之前在 ServletRequestAttributes 中设置请求对象。我删除了 RequestContextListener 并将其替换为 RequestContextFilter (似乎是他们在 spring boot 中所做的: https://github.com/spring-projects/spring-boot/issues/2637 )。这确保了当初始化 ServletRequestAttributes 时,它会获取 Hazelcast 请求对象。

最佳答案

Hazelcast WebFilter(以及 SpringAwareFilter)将请求包装在 RequestWrapper 中。当调用 request.getSession() 时,包装器会创建一个新的 HazelcastSession,或者返回现有的(如果有)。

这就是为什么 WebFilter 需要在其他过滤器之前定义。来自 hazelcast-wm's README :

Make sure Hazelcast filter is placed before all the other filters if any; you can put it at the top.

Servlet 容器在过滤器之前处理 ServletRequestListener 实例(请参阅 this answer on SO )。因此,如果 ServletRequestListener(或任何其他代码段)在 WebFilter 有机会包装请求之前调用 request.getSession(),则不会HazelcastSession 将被创建, session 复制将不起作用。

确保 Hazelcast WebFilter 在调用 request.getSession() 解决问题之前包装请求。

关于java - 作用域 bean 应如何在 Hazelcast 中触发 session 创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41058183/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com