更新问题描述以更加明确和详细。
我有 weblogic 12c ,配置了一个群集,群集中有4个节点实例,默认加载算法是循环,复制类型是 MAN < / strong>即可。我在所有4个节点上部署了一个Web应用程序。
我第一次设计的是:
一旦用户会话失效,就执行注销相关的业务逻辑。 将逻辑代码放在SessionListener.java的“sessionDestroyed”方法中,该方法实现HttpSession接口。 如您所知,会话失效可能由2个案例引起,一个是手动注销,另一个是J2ee容器触发超时。我的问题是因为第二种情况而发生的。
问题:
“SessionDestroyed”事件中的业务逻辑代码对于一个用户超时执行两次,这是不期望的并且导致业务错误。我发现节点A上的Primary Http Session和节点B上的Backup Session都触发了weblogic“SessionDestroyed”事件。
问题:
附加日志,你可以看到第一行和第二行是主会话,第三行是备份会话,可以通过行尾中的会话ID来证明。
DEBUG Oct-20-17 01:53:40 [[ACTIVE] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)'] (AMCSessionListener-27 ) - Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!-1795465203!1400921280!1508478820022 Created at Fri Oct 20 01:53:40 EDT 2017
DEBUG Oct-20-17 02:54:05 [[ACTIVE] ExecuteThread: '9' for queue: 'weblogic.kernel.Default (self-tuning)'] (AMCSessionListener-46 ) - Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!-1795465203!1400921280!1508478820022 Destroyed at Fri Oct 20 02:54:05 EDT 2017
DEBUG Oct-20-17 02:55:12 [[ACTIVE] ExecuteThread: '17' for queue: 'weblogic.kernel.Default (self-tuning)'] (AMCSessionListener-46 ) - Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!173379423!1400921280!1508478820022 Destroyed at Fri Oct 20 02:55:12 EDT 2017
以下是我的weblogic配置:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app
xmlns="http://www.bea.com/ns/weblogic/90"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">
<session-descriptor>
<cookie-path>/AppName</cookie-path>
<persistent-store-type>replicated</persistent-store-type>
<http-proxy-caching-of-cookies>true</http-proxy-caching-of-cookies>
<cookie-secure>true</cookie-secure>
</session-descriptor>
</weblogic-web-app>
这是我在Web应用程序内的web.xml中配置的会话:
<session-config>
<session-timeout>60</session-timeout>
</session-config>
这是我的SessionListener.java:
public class SessionListener implements HttpSessionListener {
private static Logger logger = Logger.getLogger(SessionListener.class);
@Override
public void sessionCreated(HttpSessionEvent se) {
if (logger.isDebugEnabled()) {
logger.debug("Session: " + se.getSession().getId() + " Created at " + (new java.util.Date()));
}
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
/**
* The business logic code related to logout action
* would be executed twice here, this is not what I want.
**/
if (logger.isDebugEnabled()) {
logger.debug("Session: " + se.getSession().getId() + " Destroyed at " + (new java.util.Date()));
}
}
}
此代码用于手动注销:
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public ModelAndView logout(HttpServletRequest request,
HttpServletResponse response) throws Exception {
...
// Business Logic for Logout
...
request.getSession().invalidate();
CommonViewObject vo = new CommonViewObject();
return renderReponse(request, response, vo, "Login");
}
任何建议都将不胜感激。我需要解决这个问题,谢谢!
答案 0 :(得分:1)
如果强制用户通过invalidate()
方法注销,则HttpSessionListener sessionDestroyed()方法会在注销时调用两次,在一段延迟时间后第二次调用。
如果在注销后您将用户重定向回应用程序中的网页,则会发生 。您实际上正在做的是开始另一个会话 (如果您没有向所有网页添加安全/身份验证要求,这可能不会立即显现),以及 sessionDestroyed()方法的第二次延迟调用是超时发生。
简单的解决方案,在注销时将用户重定向到应用程序之外的网页。
您可能有兴趣看一下:
JDev/ADF: How to log user login/logout/timeout to the database
答案 1 :(得分:0)
Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!-1795465203!1400921280!1508478820022
Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!-1795465203!1400921280!1508478820022
Session: wIc4WB62vlaYR_tMRMIc0WpBHchh5fbwpinxgaig4mJRJFhlPUcj!**173379423**!1400921280!1508478820022
第三个日志行表示在不同的主jvm /节点( 173379423 )中创建的会话比较前两个( -795465203 )。
这可能与session.invalidate调用无关,而是存在创建两个会话(两个不同的主节点)并在超时后过期的问题
我可以想到两个可能的用例
更新:
- 为什么备份会话不会触发会话创建的事件? 2.理想情况下,备份会话是否应该与主会话超时 透明?
醇>
There is no second session being created!!.
让我试着解释一下这个流程。
节点A生成会话并标记为主要会根据其群集排名(假设节点B)创建辅助备份,并将会话ID作为Cookie的一部分传递以进行进一步通信。
对LB,LB的进一步请求将检查Cookies并根据服务器标识符将其路由到节点A的流量
节点A在Lb与节点A之间出现错误/连接问题,现在LB无法根据Cookie的信息进行路由,因此LB可以根据循环选择任意节点并将请求发送到新节点(节点D)。此时,节点D根据作为部分请求传递的Cookie信息从辅助节点拉取会话,并标记为主节点,节点B将保持为次要节点。
HttpClusterServlet
代理(例如apache代理)并使用和(Weblogic插件(HttpClusterServlet
))在weblogic前面进行负载均衡,那么{{1应该能够收集您的辅助服务器信息(主机和端口)并将流量路由到辅助后台服务器。现在节点B将成为主要节点,并且将根据节点B的集群排名选择新的辅助节点。所有会话复制对客户端都应该是透明的,并且在上述情况下没有创建第二个会话。
注意**,在两种情况下(基于LB /代理的路由),在节点A中创建的会话被视为孤立,因为会话获得了新的主要和次要。因此,当用户会话无效时,它将在当前主节点和辅助节点中失效。
Weblogic documentation提供了此用例的其他信息。
建议根据访问日志/应用程序日志跟踪会话,以验证调用何时移至下一个节点。还要确保在同一时间段内访问日志中的LB运行状况监视器请求
还建议确保LB配置了Cookie持久性配置文件。
答案 2 :(得分:0)
我猜您使用默认的spring安全配置,默认启用CSRF检查,因此您可能需要禁用它并再次检查
http.csrf().disable()