From 2633da217c0d567226ad8a0bc6ce36a2aceabfdc Mon Sep 17 00:00:00 2001 From: Hai Liang Wang Date: Tue, 12 Nov 2019 20:05:23 +0800 Subject: [PATCH] Closed https://github.com/chatopera/cosin/issues/223 fix session length issue --- contact-center/Dockerfile | 2 +- .../cc/activemq/AgentSessionSubscription.java | 2 +- .../interceptor/UserInterceptorHandler.java | 17 ++++-- .../chatopera/cc/proxy/AgentSessionProxy.java | 35 ++++++++----- .../socketio/handler/AgentEventHandler.java | 35 ++++++++++--- .../cc/socketio/handler/IMEventHandler.java | 9 +++- .../main/resources/static/js/CSKeFu_IM.v1.js | 7 ++- .../static/js/CSKeFu_Rest_Request.v1.js | 4 +- .../apps/business/contacts/index.html | 52 ------------------- .../resources/templates/apps/im/mobile.html | 4 +- .../src/main/resources/templates/login.html | 2 +- 11 files changed, 85 insertions(+), 84 deletions(-) diff --git a/contact-center/Dockerfile b/contact-center/Dockerfile index df095b4c..ed02eb6a 100644 --- a/contact-center/Dockerfile +++ b/contact-center/Dockerfile @@ -14,7 +14,7 @@ RUN chmod +x /opt/install-corretto-8.sh && /opt/install-corretto-8.sh # install other lib and configure timezone RUN apt-get update && \ - apt-get install --no-install-recommends -y tzdata mysql-client-5.7 zip unzip vim-tiny && \ + apt-get install --no-install-recommends -y tzdata mysql-client-5.7 zip unzip vim-tiny libfontconfig1 libfreetype6 && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ DEBIAN_FRONTEND=noninteractive dpkg-reconfigure --frontend noninteractive tzdata && \ rm -rf /var/lib/apt/lists/* diff --git a/contact-center/app/src/main/java/com/chatopera/cc/activemq/AgentSessionSubscription.java b/contact-center/app/src/main/java/com/chatopera/cc/activemq/AgentSessionSubscription.java index bb0e3db5..85542829 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/activemq/AgentSessionSubscription.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/activemq/AgentSessionSubscription.java @@ -42,7 +42,7 @@ public class AgentSessionSubscription { // 把登出消息通知给浏览器 NettyClients.getInstance().publishLeaveEventMessage( json.get("agentno").getAsString(), - json.get("post").getAsString()); + json.get("expired").getAsString()); } catch (Exception e) { logger.warn("[onMessage] error", e); } diff --git a/contact-center/app/src/main/java/com/chatopera/cc/interceptor/UserInterceptorHandler.java b/contact-center/app/src/main/java/com/chatopera/cc/interceptor/UserInterceptorHandler.java index 00efa434..54156110 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/interceptor/UserInterceptorHandler.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/interceptor/UserInterceptorHandler.java @@ -24,6 +24,7 @@ import com.chatopera.cc.config.MessagingServerConfigure; import com.chatopera.cc.model.Dict; import com.chatopera.cc.model.SystemConfig; import com.chatopera.cc.model.User; +import com.chatopera.cc.proxy.AgentSessionProxy; import com.chatopera.cc.proxy.UserProxy; import com.chatopera.cc.util.Menu; import org.apache.commons.lang.StringUtils; @@ -40,7 +41,7 @@ import javax.servlet.http.HttpServletResponse; public class UserInterceptorHandler extends HandlerInterceptorAdapter { private final static Logger logger = LoggerFactory.getLogger(UserInterceptorHandler.class); private static UserProxy userProxy; - + private static AgentSessionProxy agentSessionProxy; private static Integer webimport; @Override @@ -48,12 +49,14 @@ public class UserInterceptorHandler extends HandlerInterceptorAdapter { throws Exception { boolean filter = false; User user = (User) request.getSession(true).getAttribute(Constants.USER_SESSION_NAME); + if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Menu menu = handlerMethod.getMethod().getAnnotation(Menu.class); if (user != null || (menu != null && menu.access()) || handlerMethod.getBean() instanceof BasicErrorController) { filter = true; if (user != null && StringUtils.isNotBlank(user.getId())) { + /** * 每次刷新用户的组织机构、角色和权限 * TODO 此处代码执行频率高,但是并不是每次都要执行,存在很多冗余 @@ -164,7 +167,7 @@ public class UserInterceptorHandler extends HandlerInterceptorAdapter { } - public static Integer getWebimport() { + private static Integer getWebimport() { if (webimport == null) { webimport = MainContext.getContext().getBean(MessagingServerConfigure.class).getWebIMPort(); } @@ -172,10 +175,18 @@ public class UserInterceptorHandler extends HandlerInterceptorAdapter { } - public static UserProxy getUserProxy() { + private static UserProxy getUserProxy() { if (userProxy == null) { userProxy = MainContext.getContext().getBean(UserProxy.class); } return userProxy; } + + private static AgentSessionProxy getAgentSessionProxy() { + if (agentSessionProxy == null) { + agentSessionProxy = MainContext.getContext().getBean(AgentSessionProxy.class); + } + return agentSessionProxy; + } + } diff --git a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentSessionProxy.java b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentSessionProxy.java index f78aeca6..087d9eb7 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentSessionProxy.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentSessionProxy.java @@ -48,31 +48,42 @@ public class AgentSessionProxy { * @param orgi */ public void updateUserSession(final String agentno, final String sessionId, final String orgi) { -// logger.info("[updateUserSession] agentno {}, sessionId {}, orgi {}", agentno, sessionId, orgi); + logger.info("[updateUserSession] agentno {}, sessionId {}, orgi {}", agentno, sessionId, orgi); if (cache.existUserSessionByAgentnoAndOrgi(agentno, orgi)) { final String preSessionId = cache.findOneSessionIdByAgentnoAndOrgi(agentno, orgi); if (StringUtils.equals(preSessionId, sessionId)) { // 现在的session和之前的是一样的,忽略更新 -// logger.info( -// "[updateUserSession] agentno {}, sessionId {} is synchronized, skip update.", agentno, -// sessionId); + logger.info( + "[updateUserSession] agentno {}, sessionId {} is synchronized, skip update.", agentno, + sessionId); return; } if (StringUtils.isNotBlank(preSessionId)) { - // 通知浏览器登出 -// logger.info("[updateUserSession] notify logut browser"); - JsonObject payload = new JsonObject(); - payload.addProperty("agentno", agentno); // 坐席ID - payload.addProperty("pre", preSessionId); // 之前的Session - payload.addProperty("orgi", orgi); // 租户Id - payload.addProperty("post", sessionId); // 之后的Id - brokerPublisher.send(Constants.MQ_TOPIC_WEB_SESSION_SSO, payload.toString(), true); + publishAgentLeaveEvent(agentno, sessionId, orgi); } } cache.putUserSessionByAgentnoAndSessionIdAndOrgi(agentno, sessionId, orgi); } + /** + * 通知浏览器登出 + * + * @param agentno + * @param expired 过期的SessionID + * @param orgi + */ + public void publishAgentLeaveEvent(final String agentno, final String expired, final String orgi) { + // + logger.info("[publishAgentLeaveEvent] notify logut browser, expired session {}", expired); + JsonObject payload = new JsonObject(); + payload.addProperty("agentno", agentno); // 坐席ID + payload.addProperty("orgi", orgi); // 租户Id + payload.addProperty("expired", expired); // 之后的Id + brokerPublisher.send(Constants.MQ_TOPIC_WEB_SESSION_SSO, payload.toString(), true); + } + + /** * 是否是"不合法"的Session信息 * diff --git a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java index 9a62c6a5..753bd420 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java @@ -186,8 +186,13 @@ public class AgentEventHandler { final SocketIOClient client, final AckRequest request, final InterventMessage received) throws JsonProcessingException { + final String agentno = client.get("agentno"); + final String session = client.get("session"); + final String connectid = client.get("connectid"); logger.info( - "[onEvent] intervention: {}", received.toJsonObject()); + "[onIntervetionEvent] intervention: agentno {}, session {}, connectid {}, payload {}", agentno, session, connectid, + received.toJsonObject()); + if (received.valid()) { // 获得AgentUser @@ -195,9 +200,11 @@ public class AgentEventHandler { // 验证当前的SSO中的session是否和传入的session匹配 if (getAgentSessionProxy().isInvalidSessionId( - received.getSupervisorid(), received.getSession(), agentUser.getOrgi())) { + agentno, session, agentUser.getOrgi())) { // 该session信息不合法 - logger.info("[onConnect] invalid sessionId {}", received.getSession()); + logger.info("[onIntervetionEvent] invalid sessionId {}", session); + // 强制退出 + client.sendEvent(MainContext.MessageType.LEAVE.toString()); return; } @@ -265,19 +272,35 @@ public class AgentEventHandler { final SocketIOClient client, final AckRequest request, final ChatMessage received) throws IOException { + final String agentno = client.get("agentno"); + final String session = client.get("session"); + final String connectid = client.get("connectid"); + received.setSessionid(session); // 此处user代表坐席的ID - String agentno = client.getHandshakeData().getSingleUrlParam("userid"); +// String agentno = client.getHandshakeData().getSingleUrlParam("userid"); logger.info( - "[onEvent] message: agentUserId {}, agentno {}, toUser {}, channel {}, orgi {}, appId {}, userId {}, sessionId {}", + "[onMessageEvent] message: agentUserId {}, agentno {}, toUser {}, channel {}, orgi {}, appId {}, userId {}, sessionId {}, connectid {}", received.getAgentuser(), agentno, received.getTouser(), received.getChannel(), received.getOrgi(), received.getAppid(), received.getUserid(), - received.getSessionid()); + session, connectid); + + + // 验证当前的SSO中的session是否和传入的session匹配 + if (getAgentSessionProxy().isInvalidSessionId( + agentno, session, received.getOrgi())) { + // 该session信息不合法 + logger.info("[onMessageEvent] invalid sessionId {}", session); + // 强制退出 + client.sendEvent(MainContext.MessageType.LEAVE.toString()); + return; + } AgentUser agentUser = MainContext.getCache().findOneAgentUserByUserIdAndOrgi( received.getTouser(), received.getOrgi()).orElseGet(null); + /** * 判断用户在线状态,如果用户在线则通过webim发送 * 检查收发双方的信息匹配 diff --git a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java index 94e12d39..0294b73d 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java @@ -70,7 +70,7 @@ public class IMEventHandler { try { final String user = client.getHandshakeData().getSingleUrlParam("userid"); final String orgi = client.getHandshakeData().getSingleUrlParam("orgi"); - final String session = client.getHandshakeData().getSingleUrlParam("session"); + final String session = MainUtils.getContextID(client.getHandshakeData().getSingleUrlParam("session")); final String appid = client.getHandshakeData().getSingleUrlParam("appid"); final String agent = client.getHandshakeData().getSingleUrlParam("agent"); final String skill = client.getHandshakeData().getSingleUrlParam("skill"); @@ -88,6 +88,11 @@ public class IMEventHandler { "[onConnect] user {}, orgi {}, session {}, appid {}, agent {}, skill {}, title {}, url {}, traceid {}, nickname {}", user, orgi, session, appid, agent, skill, title, url, traceid, nickname); + // save connection info + client.set("session", session); + client.set("userid", user); + client.set("appid", appid); + if (StringUtils.isNotBlank(user)) { InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress(); String ip = MainUtils.getIpAddr(client.getHandshakeData().getHttpHeaders(), address.getHostString()); @@ -189,7 +194,7 @@ public class IMEventHandler { , orgi); }); } catch (Exception e) { - e.printStackTrace(); + logger.warn("[onDisconnect] error", e); } NettyClients.getInstance().removeIMEventClient( user, MainUtils.getContextID(client.getSessionId().toString())); diff --git a/contact-center/app/src/main/resources/static/js/CSKeFu_IM.v1.js b/contact-center/app/src/main/resources/static/js/CSKeFu_IM.v1.js index 38f10eb4..ec8519b6 100644 --- a/contact-center/app/src/main/resources/static/js/CSKeFu_IM.v1.js +++ b/contact-center/app/src/main/resources/static/js/CSKeFu_IM.v1.js @@ -101,8 +101,11 @@ $(document).ready(function(){ $('#agentdesktop').attr('data-href', '/agent/index.html?userid='+data.userid).click(); } }).on('leave', function(data){ - // 执行登出 - window.location.href = "/logout.html?code=2"; + top.layer.msg('当前会话已经过期,稍后将自动登出!',{icon: 1, time: 2000}); + setTimeout(function(){ + // 执行登出 + window.location.href = "/logout.html?code=2"; + }, 2000); }); /****每分钟执行一次,与服务器交互,保持会话****/ setInterval(function(){ diff --git a/contact-center/app/src/main/resources/static/js/CSKeFu_Rest_Request.v1.js b/contact-center/app/src/main/resources/static/js/CSKeFu_Rest_Request.v1.js index e681e24a..59bad09a 100644 --- a/contact-center/app/src/main/resources/static/js/CSKeFu_Rest_Request.v1.js +++ b/contact-center/app/src/main/resources/static/js/CSKeFu_Rest_Request.v1.js @@ -57,13 +57,13 @@ function restApiRequest(opts) { // 操作成功的 function handleRestApiSucc(msg) { - layer.msg( msg || '操作成功',{icon: 1, offset: 'b', time: 1000}) + layer.msg( msg || '操作成功',{icon: 1, time: 1000}) } // 操作失败的 function handleRestApiFail(status, reason) { if(status && status === 'AUTH_ERROR'){ - layer.msg('会话过期,请重新登录!',{icon: 2, offset: 'b', time: 3000}); + layer.msg('会话过期,请重新登录!',{icon: 2, time: 3000}); setTimeout(function(){ // 执行登出 window.location.href = "/logout.html"; diff --git a/contact-center/app/src/main/resources/templates/apps/business/contacts/index.html b/contact-center/app/src/main/resources/templates/apps/business/contacts/index.html index fc964515..325c2631 100644 --- a/contact-center/app/src/main/resources/templates/apps/business/contacts/index.html +++ b/contact-center/app/src/main/resources/templates/apps/business/contacts/index.html @@ -36,13 +36,6 @@ 新建联系人 - <#if user?? && (user.roleAuthMap[ "A02_A01_A02_B08"]?? || user.admin)> -
- -
- <#if user?? && (user.roleAuthMap[ "A02_A01_A02_B08"]?? || user.admin)>