diff --git a/pear-common/src/main/java/com/pearadmin/common/web/listenerr/SecuritySessionListener.java b/pear-common/src/main/java/com/pearadmin/common/web/listenerr/SecuritySessionListener.java index 508caf4993e1ba19d07acc1219148bd16db447a6..9f0653ac06652d327be129739b0867e1a9fe4fa3 100644 --- a/pear-common/src/main/java/com/pearadmin/common/web/listenerr/SecuritySessionListener.java +++ b/pear-common/src/main/java/com/pearadmin/common/web/listenerr/SecuritySessionListener.java @@ -6,13 +6,13 @@ import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; + /** - * @Author: Heiky - * @Date: 2020/12/17 17:42 - * @Description: + * Describe: 自定义HttpSessionListener + * Author: Heiky + * CreateTime: 2020/12/17 */ - -@WebListener("自定义HttpSession监听器") +@WebListener public class SecuritySessionListener implements HttpSessionListener { private HttpSessionContext sessionContext = HttpSessionContext.getInstance(); diff --git a/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContext.java b/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContext.java index ca936c18ee02317b8d7fd2f60f60d49c5edc30b2..8c3048d58791997b839473169b2d6323f4f6d929 100644 --- a/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContext.java +++ b/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContext.java @@ -4,10 +4,11 @@ import javax.servlet.http.HttpSession; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + /** - * @Author: Heiky - * @Date: 2020/12/17 17:14 - * @Description: 单例模式 HttpSessionContext + * Describe: 单例模式 HttpSessionContext + * Author: Heiky + * CreateTime: 2020/12/17 */ public class HttpSessionContext { diff --git a/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContextHolder.java b/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContextHolder.java index 1a964e66a3fd36408be1e141dc7b08ac2bb86d75..0ee9294feaf0574c4cbe0f62fbeb1be65857f4c5 100644 --- a/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContextHolder.java +++ b/pear-common/src/main/java/com/pearadmin/common/web/session/HttpSessionContextHolder.java @@ -1,9 +1,10 @@ package com.pearadmin.common.web.session; + /** - * @Author: Heiky - * @Date: 2020/12/17 17:47 - * @Description: HttpSessionContext对象持有者 + * Describe: HttpSessionContext对象持有者 + * Author: Heiky + * CreateTime: 2020/12/17 */ public class HttpSessionContextHolder { diff --git a/pear-entrance/src/main/java/com/pearadmin/api/runner/RemoveInvalidSession.java b/pear-entrance/src/main/java/com/pearadmin/api/runner/RemoveInvalidSession.java index fae342f4bc6f28b16dc17461e9fd381235413c50..1022d7159330245ac1313e63dea05f3423cc31cf 100644 --- a/pear-entrance/src/main/java/com/pearadmin/api/runner/RemoveInvalidSession.java +++ b/pear-entrance/src/main/java/com/pearadmin/api/runner/RemoveInvalidSession.java @@ -1,5 +1,6 @@ package com.pearadmin.api.runner; +import com.pearadmin.common.web.session.HttpSessionContextHolder; import com.pearadmin.system.domain.SysUser; import lombok.extern.slf4j.Slf4j; import org.activiti.engine.impl.util.CollectionUtil; @@ -9,7 +10,9 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.stereotype.Component; + import javax.annotation.Resource; +import javax.servlet.http.HttpSession; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; @@ -25,8 +28,7 @@ import java.util.concurrent.TimeUnit; @Component public class RemoveInvalidSession implements CommandLineRunner { - @Resource - @Qualifier("manageSessionThreadPool") + @Resource(name = "manageSessionThreadPool") private ScheduledThreadPoolExecutor manageSessionThreadPool; @Resource @@ -38,6 +40,7 @@ public class RemoveInvalidSession implements CommandLineRunner { @Override public void run(String... args) throws Exception { manageSessionThreadPool.scheduleWithFixedDelay(() -> { + // 从sessionRegistry中获取所有的用户信息 List principals = sessionRegistry.getAllPrincipals(); for (Object principal : principals) { SysUser userDetails = (SysUser) principal; @@ -50,10 +53,13 @@ public class RemoveInvalidSession implements CommandLineRunner { List sessionInformationList = sessionRegistry.getAllSessions(userDetails, false); if (CollectionUtil.isNotEmpty(sessionInformationList)) { for (SessionInformation sessionInformation : sessionInformationList) { - // 清除已经过期的session + // 清除已经过期的session(SessionRegistry) sessionInformation.expireNow(); sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); - log.info(String.format("HttpSessionId[%s]------>已从sessionRegistry中移除", sessionInformation.getSessionId())); + log.info(String.format("HttpSessionId[%s]------>已从SessionRegistry中移除", sessionInformation.getSessionId())); + // 销毁已经过期的session + HttpSessionContextHolder.currentSessionContext().getSession(sessionInformation.getSessionId()).invalidate(); + log.info(String.format("HttpSessionId[%s]------>已从HttpSessionContext中移除", sessionInformation.getSessionId())); } } } else { diff --git a/pear-entrance/src/main/java/com/pearadmin/security/BeanConfig.java b/pear-entrance/src/main/java/com/pearadmin/security/BeanConfig.java index 1a7dc93c2deb2d01e56a3e445d82b6e1792680f7..9511f2ec895cab9158507f408a57fc4aca8af269 100644 --- a/pear-entrance/src/main/java/com/pearadmin/security/BeanConfig.java +++ b/pear-entrance/src/main/java/com/pearadmin/security/BeanConfig.java @@ -13,6 +13,7 @@ import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect; import org.thymeleaf.spring5.ISpringTemplateEngine; import org.thymeleaf.spring5.SpringTemplateEngine; import org.thymeleaf.templateresolver.ITemplateResolver; + import javax.annotation.Resource; import java.util.concurrent.ScheduledThreadPoolExecutor; @@ -20,7 +21,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; * Describe: Security Configuration 配置扩展 (Security Configuration 部分) * Author: Heiky * CreateTime: 2020/12/17 - * */ + */ @Configuration public class BeanConfig { @@ -68,6 +69,9 @@ public class BeanConfig { return templateEngine; } + /** + * 注册HttpSessionEventPublisher,发布HttpSessionEvent + */ @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); @@ -84,6 +88,9 @@ public class BeanConfig { return new SecurityLogoutHandler(httpSessionEventPublisher); } + /** + * 注册ScheduledThreadPoolExecutor,进行在线用户用户检测,清除过期Session + */ @Bean public ScheduledThreadPoolExecutor manageSessionThreadPool() { ScheduledThreadPoolExecutor executor = diff --git a/pear-entrance/src/main/java/com/pearadmin/security/process/SecurityLogoutHandler.java b/pear-entrance/src/main/java/com/pearadmin/security/process/SecurityLogoutHandler.java index c99469ea304710f6ae63bf91b5c5b5f80965fa81..3c1da81585cf3eb1126de5f0102b6652aef2afb3 100644 --- a/pear-entrance/src/main/java/com/pearadmin/security/process/SecurityLogoutHandler.java +++ b/pear-entrance/src/main/java/com/pearadmin/security/process/SecurityLogoutHandler.java @@ -1,5 +1,6 @@ package com.pearadmin.security.process; +import com.pearadmin.common.web.session.HttpSessionContextHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; @@ -18,7 +19,7 @@ import javax.servlet.http.HttpSessionEvent; * Describe: 自定义用户注销处理类 * Author: Heiky * CreateTime: 2020/12/17 - * */ + */ public class SecurityLogoutHandler implements LogoutHandler { private static final Logger log = LoggerFactory.getLogger(SecurityLogoutHandler.class); @@ -43,16 +44,20 @@ public class SecurityLogoutHandler implements LogoutHandler { if (httpSessionEventPublisher != null) { // 构建要销毁的session HttpSessionEvent sessionEvent = new HttpSessionEvent(request.getSession()); + // 发布session销毁事件 httpSessionEventPublisher.sessionDestroyed(sessionEvent); } + // 销毁session if (invalidateHttpSession) { HttpSession session = request.getSession(false); + // 移除HttpSessionContext中的session信息 + HttpSessionContextHolder.currentSessionContext().removeSession(session); if (session != null) { log.debug("Invalidating session: " + session.getId()); session.invalidate(); } } - + // 清空Authentication if (clearAuthentication) { SecurityContext context = SecurityContextHolder.getContext(); context.setAuthentication(null); diff --git a/pear-entrance/src/main/java/com/pearadmin/security/session/HttpSessionUtil.java b/pear-entrance/src/main/java/com/pearadmin/security/session/HttpSessionUtil.java index 5196f030e5dc797cf5108e9ff7713403ef225c6e..a46a8d4dabfffbc03e6d7fd20193d582c59c9bb7 100644 --- a/pear-entrance/src/main/java/com/pearadmin/security/session/HttpSessionUtil.java +++ b/pear-entrance/src/main/java/com/pearadmin/security/session/HttpSessionUtil.java @@ -1,10 +1,13 @@ package com.pearadmin.security.session; +import com.pearadmin.common.web.session.HttpSessionContext; +import com.pearadmin.common.web.session.HttpSessionContextHolder; import com.pearadmin.system.domain.SysUser; import org.activiti.engine.impl.util.CollectionUtil; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import java.util.List; /** @@ -23,18 +26,26 @@ public class HttpSessionUtil { public static void expiredSession(HttpServletRequest request, SessionRegistry sessionRegistry) { SysUser currentUser = (SysUser) request.getSession().getAttribute("currentUser"); String sessionId = request.getSession().getId(); + // 从sessionRegistry中获取所有的用户信息 List principals = sessionRegistry.getAllPrincipals(); for (Object principal : principals) { SysUser userDetails = (SysUser) principal; + // 若sessionRegistry中的userDetails的用户名与当前用户的用户名相同 if (userDetails != null && userDetails.getUsername().equals(currentUser.getUsername())) { + // 查询用户所有的SessionInformation,包括过期session List sessionInformationList = sessionRegistry.getAllSessions(userDetails, true); if (CollectionUtil.isNotEmpty(sessionInformationList)) { for (SessionInformation sessionInformation : sessionInformationList) { + // 不处理当前用户的session if (sessionId.equals(sessionInformation.getSessionId())) { continue; } + // 从sessionRegistry中清除session信息 sessionInformation.expireNow(); sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); + // 从HttpSessionContext中清除session信息 + HttpSession httpSession = HttpSessionContextHolder.currentSessionContext().getSession(sessionInformation.getSessionId()); + HttpSessionContextHolder.currentSessionContext().removeSession(httpSession); } } } diff --git a/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysLoggingController.java b/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysLoggingController.java index 049b09e017d9c4fd95a0f5f0d2aa0f7fde2c28c6..dbbf4f5cf5055044a9f3d639350a8260037853b5 100644 --- a/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysLoggingController.java +++ b/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysLoggingController.java @@ -31,10 +31,6 @@ import java.util.Map; @RequestMapping("system/logging") public class SysLoggingController extends BaseController { - - @Autowired - private ObjectMapper objectMapper; - /** * 引 入 日 志 组 件 的 日 志 服 务 */ diff --git a/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysOnlineUserController.java b/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysOnlineUserController.java index 694992c66068bedc653d4f2d99174c33b2201e62..e00317bfc3198f5c86e8e341b1cb24adbbb07a41 100644 --- a/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysOnlineUserController.java +++ b/pear-modules/pear-system/src/main/java/com/pearadmin/system/controller/SysOnlineUserController.java @@ -50,7 +50,6 @@ public class SysOnlineUserController extends BaseController { sysOnlineUser.setUsername(objs.getUsername()); sysOnlineUser.setRealName(objs.getRealName()); sysOnlineUser.setLastTime(objs.getLastTime()); - System.out.println(objs.getLastTime()); sysOnlineUser.setOnlineTime(Duration.between(objs.getLastTime(), LocalDateTime.now()).toMinutes() + "分钟"); onlineUser.add(sysOnlineUser); } @@ -58,6 +57,10 @@ public class SysOnlineUserController extends BaseController { return dataTable(onlineUser); } + /** + * Describe: 获取在线用户列表视图 + * Return: ModelAndView + */ @GetMapping("main") @PreAuthorize("hasPermission('/system/online/main','sys:online:main')") public ModelAndView main() { @@ -65,19 +68,27 @@ public class SysOnlineUserController extends BaseController { } + /** + * Describe: 踢出用户(下线) + * Param: onlineId + * Return: ModelAndView + */ @DeleteMapping("/remove/{onlineId}") @ResponseBody public Result remove(@PathVariable String onlineId) { + // 从sessionRegistry中获取所有的用户信息 List principals = sessionRegistry.getAllPrincipals(); for (Object principal : principals) { SysUser userDetails = (SysUser) principal; String userId = userDetails.getUserId(); if (onlineId.equals(userId)) { + // 不允许操作admin用户下线 if ("admin".equals(userDetails.getUsername())) { return failure("不允许操作超级管理员[admin]下线"); } for (SessionInformation sessionInformation : sessionRegistry.getAllSessions(userDetails, false)) { sessionInformation.expireNow(); + // 从sessionRegistry中清除session信息 sessionRegistry.removeSessionInformation(sessionInformation.getSessionId()); HttpSessionContext sessionContext = HttpSessionContextHolder.currentSessionContext(); // 销毁session