From 84333544560aec1f3be03e9870631936d039a7a1 Mon Sep 17 00:00:00 2001 From: xiangpei <xiangpei@timesnew.cn> Date: 星期四, 11 七月 2024 09:47:37 +0800 Subject: [PATCH] 增加session过滤器,阻止同一个用户同时登录 --- src/main/java/com/ycl/jxkg/config/spring/security/RestAuthenticationSuccessHandler.java | 10 ++++ src/main/java/com/ycl/jxkg/config/spring/security/RestLoginAuthenticationFilter.java | 8 ++++ src/main/java/com/ycl/jxkg/utils/CaffeineUtil.java | 13 ++++++ src/main/java/com/ycl/jxkg/config/spring/security/SecurityConfigurer.java | 7 +++ src/main/java/com/ycl/jxkg/config/spring/security/SessionFilter.java | 61 ++++++++++++++++++++++++++++++ src/main/java/com/ycl/jxkg/config/spring/security/RestLogoutSuccessHandler.java | 10 ++++ 6 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ycl/jxkg/config/spring/security/RestAuthenticationSuccessHandler.java b/src/main/java/com/ycl/jxkg/config/spring/security/RestAuthenticationSuccessHandler.java index a5ead92..58df9d5 100644 --- a/src/main/java/com/ycl/jxkg/config/spring/security/RestAuthenticationSuccessHandler.java +++ b/src/main/java/com/ycl/jxkg/config/spring/security/RestAuthenticationSuccessHandler.java @@ -1,10 +1,12 @@ package com.ycl.jxkg.config.spring.security; import com.ycl.jxkg.base.SystemCode; +import com.ycl.jxkg.constants.CaffeineConstant; import com.ycl.jxkg.domain.entity.UserEventLog; import com.ycl.jxkg.enums.general.YesOrNoEnum; import com.ycl.jxkg.event.UserEvent; import com.ycl.jxkg.service.UserService; +import com.ycl.jxkg.utils.CaffeineUtil; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; @@ -12,6 +14,7 @@ import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -31,6 +34,7 @@ private final ApplicationEventPublisher eventPublisher; private final UserService userService; + private final CaffeineUtil caffeineUtil; /** * Instantiates a new Rest authentication success handler. @@ -39,9 +43,10 @@ * @param userService the user service */ @Autowired - public RestAuthenticationSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService) { + public RestAuthenticationSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService, CaffeineUtil caffeineUtil) { this.eventPublisher = eventPublisher; this.userService = userService; + this.caffeineUtil = caffeineUtil; } @Override @@ -49,6 +54,9 @@ Object object = authentication.getPrincipal(); if (null != object) { User springUser = (User) object; + // 鐧诲綍涔嬪悗淇濆瓨鎴栨洿鏂� 鐢ㄦ埛鍚嶄笌session鐨勫叧绯� + String sessionId = request.getSession().getId(); + caffeineUtil.put(CaffeineConstant.AUTH, springUser.getUsername(), sessionId); com.ycl.jxkg.domain.entity.User user = userService.getUserByUserName(springUser.getUsername()); if (null != user) { // 瀵嗙爜杩囨湡杩斿洖寮哄埗淇敼瀵嗙爜鏍囪瘑 diff --git a/src/main/java/com/ycl/jxkg/config/spring/security/RestLoginAuthenticationFilter.java b/src/main/java/com/ycl/jxkg/config/spring/security/RestLoginAuthenticationFilter.java index 21f7f13..5407567 100644 --- a/src/main/java/com/ycl/jxkg/config/spring/security/RestLoginAuthenticationFilter.java +++ b/src/main/java/com/ycl/jxkg/config/spring/security/RestLoginAuthenticationFilter.java @@ -2,8 +2,10 @@ import com.ycl.jxkg.config.property.CookieConfig; +import com.ycl.jxkg.utils.CaffeineUtil; import com.ycl.jxkg.utils.JsonUtil; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -16,6 +18,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; +import java.util.Enumeration; /** @@ -25,7 +28,11 @@ * @date 2021/12/25 9:45 */ public class RestLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + private final org.slf4j.Logger logger = LoggerFactory.getLogger(RestLoginAuthenticationFilter.class); + + @Autowired + private CaffeineUtil caffeineUtil; /** * Instantiates a new Rest login authentication filter. @@ -40,6 +47,7 @@ try (InputStream is = request.getInputStream()) { AuthenticationBean authenticationBean = JsonUtil.toJsonObject(is, AuthenticationBean.class); request.setAttribute(TokenBasedRememberMeServices.DEFAULT_PARAMETER, authenticationBean.isRemember()); + authRequest = new UsernamePasswordAuthenticationToken(authenticationBean.getUserName(), authenticationBean.getPassword()); } catch (IOException e) { logger.error(e.getMessage(), e); diff --git a/src/main/java/com/ycl/jxkg/config/spring/security/RestLogoutSuccessHandler.java b/src/main/java/com/ycl/jxkg/config/spring/security/RestLogoutSuccessHandler.java index 9a35774..5517844 100644 --- a/src/main/java/com/ycl/jxkg/config/spring/security/RestLogoutSuccessHandler.java +++ b/src/main/java/com/ycl/jxkg/config/spring/security/RestLogoutSuccessHandler.java @@ -1,13 +1,16 @@ package com.ycl.jxkg.config.spring.security; import com.ycl.jxkg.base.SystemCode; +import com.ycl.jxkg.constants.CaffeineConstant; import com.ycl.jxkg.domain.entity.User; import com.ycl.jxkg.domain.entity.UserEventLog; import com.ycl.jxkg.event.UserEvent; import com.ycl.jxkg.service.UserService; +import com.ycl.jxkg.utils.CaffeineUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.stereotype.Component; @@ -27,6 +30,7 @@ private final ApplicationEventPublisher eventPublisher; private final UserService userService; + private final CaffeineUtil caffeineUtil; /** * Instantiates a new Rest logout success handler. @@ -35,15 +39,19 @@ * @param userService the user service */ @Autowired - public RestLogoutSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService) { + public RestLogoutSuccessHandler(ApplicationEventPublisher eventPublisher, UserService userService, CaffeineUtil caffeineUtil) { this.eventPublisher = eventPublisher; this.userService = userService; + this.caffeineUtil = caffeineUtil; } @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { org.springframework.security.core.userdetails.User springUser = (org.springframework.security.core.userdetails.User) authentication.getPrincipal(); if (null != springUser) { + // 娓呴櫎鐢ㄦ埛鍚嶅拰sessionId涔嬮棿鐨勭粦瀹� + caffeineUtil.remove(CaffeineConstant.AUTH, springUser.getUsername()); + SecurityContextHolder.clearContext(); User user = userService.getUserByUserName(springUser.getUsername()); UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date()); userEventLog.setContent(user.getUserName() + " 鐧诲嚭浜嗗涔嬫�濆紑婧愯�冭瘯绯荤粺"); diff --git a/src/main/java/com/ycl/jxkg/config/spring/security/SecurityConfigurer.java b/src/main/java/com/ycl/jxkg/config/spring/security/SecurityConfigurer.java index 596abfb..3bf787b 100644 --- a/src/main/java/com/ycl/jxkg/config/spring/security/SecurityConfigurer.java +++ b/src/main/java/com/ycl/jxkg/config/spring/security/SecurityConfigurer.java @@ -67,6 +67,12 @@ this.restAccessDeniedHandler = restAccessDeniedHandler; } + @Bean + public SessionFilter sessionFilter() throws Exception { + SessionFilter jwtTokenFilter = new SessionFilter(authenticationManagerBean()); + return jwtTokenFilter; + } + /** * @param http http * @throws Exception exception @@ -95,6 +101,7 @@ .and().rememberMe().key(CookieConfig.getName()).tokenValiditySeconds(CookieConfig.getInterval()).userDetailsService(formDetailsService) .and().csrf().disable() .cors(); + http.addFilter(sessionFilter()); } diff --git a/src/main/java/com/ycl/jxkg/config/spring/security/SessionFilter.java b/src/main/java/com/ycl/jxkg/config/spring/security/SessionFilter.java new file mode 100644 index 0000000..c458a10 --- /dev/null +++ b/src/main/java/com/ycl/jxkg/config/spring/security/SessionFilter.java @@ -0,0 +1,61 @@ +package com.ycl.jxkg.config.spring.security; + + +import com.ycl.jxkg.base.SystemCode; +import com.ycl.jxkg.constants.CaffeineConstant; +import com.ycl.jxkg.utils.CaffeineUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Objects; + +/** + * @author 29443 + * @date 2022/4/4 + */ +@Slf4j +public class SessionFilter extends BasicAuthenticationFilter { + + @Autowired + private CaffeineUtil caffeineUtil; + + public SessionFilter(AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + // 妫�鏌ヨ姹備腑鏄惁鏈塻ecurity璁剧疆鐨勮璇佷俊鎭�傛病鏈夌殑璇濇湰Filter涓嶅仛澶勭悊 + SecurityContextImpl securityContext = (SecurityContextImpl) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); + if (Objects.isNull(securityContext)) { + chain.doFilter(request, response); + return; + } + // 鏈夌殑璇濋獙璇� + Authentication authentication = securityContext.getAuthentication(); + User authUser = (User) authentication.getPrincipal(); + // 妫�鏌ヨ繖涓敤鎴峰搴旂殑sessionId鏄惁鍜岀櫥褰曟椂鐨剆essionId鐩哥瓑 + String loginSessionId = (String) caffeineUtil.get(CaffeineConstant.AUTH, authUser.getUsername()); + if (! request.getSession().getId().equals(loginSessionId)) { + log.warn("妫�娴嬪埌鍚屼竴璐﹀彿涓や釜娴忚鍣ㄧ櫥褰�"); + RestUtil.response(response, SystemCode.UNAUTHORIZED.getCode(), "褰撳墠鐧诲綍宸插け鏁�"); + } else { + chain.doFilter(request, response); + } + } +} diff --git a/src/main/java/com/ycl/jxkg/utils/CaffeineUtil.java b/src/main/java/com/ycl/jxkg/utils/CaffeineUtil.java index 05ba205..324a26c 100644 --- a/src/main/java/com/ycl/jxkg/utils/CaffeineUtil.java +++ b/src/main/java/com/ycl/jxkg/utils/CaffeineUtil.java @@ -56,6 +56,19 @@ } /** + * 鍒犻櫎 + * + * @param database 鏁版嵁搴�/ caffeine map鐨刱ey + * @param key map鐨刱ey + */ + public void remove(String database, String key) { + Map<String, Object> map = (Map<String, Object>) caffeineCache.getIfPresent(database); + if (Objects.nonNull(map)) { + map.remove(key); + } + } + + /** * 鍒涘缓key * * @param database -- Gitblit v1.8.0