diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationLogoutEventHandler.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationLogoutEventHandler.java new file mode 100644 index 000000000..4d471c4ac --- /dev/null +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationLogoutEventHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pigx.auth.handler; + +import com.pig4cloud.pigx.admin.api.dto.SysLogDTO; +import com.pig4cloud.pigx.admin.api.feign.RemoteLogService; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.core.util.KeyStrResolver; +import com.pig4cloud.pigx.common.log.util.SysLogUtils; +import com.pig4cloud.pigx.common.security.handler.AuthenticationLogoutHandler; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.scheduling.annotation.Async; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 退出事件处理 + * + * @author lengleng + * @date 2021/06/22 + */ +@Slf4j +@Component +@AllArgsConstructor +public class PigxAuthenticationLogoutEventHandler implements AuthenticationLogoutHandler { + + private final RemoteLogService logService; + + private final KeyStrResolver tenantKeyStrResolver; + + /** + * 处理登录成功方法 + *

+ * 获取到登录的authentication 对象 + * @param authentication 登录对象 + * @param request 请求 + * @param response 返回 + */ + @Async + @Override + public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { + String username = authentication.getName(); + SysLogDTO sysLog = SysLogUtils.getSysLog(request, username); + sysLog.setTitle(username + "用户退出"); + sysLog.setParams(username); + + // 获取clientId 信息 + OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication; + sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId()); + sysLog.setTenantId(Integer.parseInt(tenantKeyStrResolver.key())); + // 保存退出的token + String token = request.getHeader(HttpHeaders.AUTHORIZATION); + sysLog.setParams(token); + + logService.saveLog(sysLog, SecurityConstants.FROM_IN); + log.info("用户:{} 退出成功, token:{} 已注销", username, token); + } + +} diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java index 99f0bf419..c53df1071 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/handler/PigxAuthenticationSuccessEventHandler.java @@ -17,9 +17,6 @@ package com.pig4cloud.pigx.auth.handler; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import com.pig4cloud.pigx.admin.api.dto.SysLogDTO; import com.pig4cloud.pigx.admin.api.feign.RemoteLogService; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; @@ -29,12 +26,14 @@ import com.pig4cloud.pigx.common.log.util.SysLogUtils; import com.pig4cloud.pigx.common.security.handler.AuthenticationSuccessHandler; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; - import org.springframework.http.HttpHeaders; import org.springframework.scheduling.annotation.Async; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * @author lengleng * @date 2018/10/8 diff --git a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/service/PigxTokenDealServiceImpl.java b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/service/PigxTokenDealServiceImpl.java index dd83cd60c..76b7cfacb 100644 --- a/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/service/PigxTokenDealServiceImpl.java +++ b/pigx-auth/src/main/java/com/pig4cloud/pigx/auth/service/PigxTokenDealServiceImpl.java @@ -6,6 +6,7 @@ import com.pig4cloud.pigx.common.core.constant.CacheConstants; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.core.util.KeyStrResolver; import com.pig4cloud.pigx.common.core.util.R; +import com.pig4cloud.pigx.common.core.util.SpringContextHolder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.CacheManager; @@ -15,13 +16,13 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.security.authentication.event.LogoutSuccessEvent; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2RefreshToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.stereotype.Service; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -67,6 +68,9 @@ public class PigxTokenDealServiceImpl { // 清空 refresh token OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); tokenStore.removeRefreshToken(refreshToken); + + // 发送退出成功事件 + SpringContextHolder.publishEvent(new LogoutSuccessEvent(auth2Authentication)); return R.ok(); } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/AuthenticationLogoutHandler.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/AuthenticationLogoutHandler.java new file mode 100644 index 000000000..757b41adb --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/AuthenticationLogoutHandler.java @@ -0,0 +1,22 @@ +package com.pig4cloud.pigx.common.security.handler; + +import org.springframework.security.core.Authentication; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author lengleng + * @date 2021/06/22 退出后置处理 + */ +public interface AuthenticationLogoutHandler { + + /** + * 业务处理 + * @param authentication 认证信息 + * @param request 请求信息 + * @param response 响应信息 + */ + void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response); + +} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/listener/AuthenticationLogoutSuccessEventListener.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/listener/AuthenticationLogoutSuccessEventListener.java new file mode 100644 index 000000000..327ad62f6 --- /dev/null +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/listener/AuthenticationLogoutSuccessEventListener.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pigx.common.security.listener; + +import cn.hutool.core.collection.CollUtil; +import com.pig4cloud.pigx.common.security.handler.AuthenticationLogoutHandler; +import com.pig4cloud.pigx.common.security.service.PigxUser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.security.authentication.event.LogoutSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author lengleng + * @date 2021/06/22 退出事件监听器 + */ +public class AuthenticationLogoutSuccessEventListener implements ApplicationListener { + + @Autowired(required = false) + private AuthenticationLogoutHandler logoutHandler; + + /** + * Handle an application event. + * @param event the event to respond to + */ + @Override + public void onApplicationEvent(LogoutSuccessEvent event) { + OAuth2Authentication authentication = (OAuth2Authentication) event.getSource(); + if (logoutHandler != null && isUserAuthentication(authentication)) { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder + .getRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + HttpServletResponse response = requestAttributes.getResponse(); + + logoutHandler.handle(authentication, request, response); + } + } + + private boolean isUserAuthentication(Authentication authentication) { + return authentication.getPrincipal() instanceof PigxUser + || CollUtil.isNotEmpty(authentication.getAuthorities()); + } + +} diff --git a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories index b4b40cec0..a35a29590 100644 --- a/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories +++ b/pigx-common/pigx-common-security/src/main/resources/META-INF/spring.factories @@ -4,5 +4,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.pig4cloud.pigx.common.security.service.PigxUserDetailsServiceImpl,\ com.pig4cloud.pigx.common.security.serializer.PigxTokenStoreAutoConfiguration,\ com.pig4cloud.pigx.common.security.listener.AuthenticationFailureEventListener,\ - com.pig4cloud.pigx.common.security.listener.AuthenticationSuccessEventListener + com.pig4cloud.pigx.common.security.listener.AuthenticationSuccessEventListener,\ + com.pig4cloud.pigx.common.security.listener.AuthenticationLogoutSuccessEventListener