diff --git a/pigx-app-server/pigx-app-server-api/pom.xml b/pigx-app-server/pigx-app-server-api/pom.xml index 18d4e9f5c..e6878cb57 100644 --- a/pigx-app-server/pigx-app-server-api/pom.xml +++ b/pigx-app-server/pigx-app-server-api/pom.xml @@ -33,5 +33,10 @@ com.pig4cloud pigx-common-excel + + + com.pig4cloud + pigx-common-sensitive + diff --git a/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/entity/AppSocialDetails.java b/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/entity/AppSocialDetails.java index 9371d7601..d5cba8300 100644 --- a/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/entity/AppSocialDetails.java +++ b/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/entity/AppSocialDetails.java @@ -19,13 +19,13 @@ package com.pig4cloud.pigx.app.api.entity; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; import com.pig4cloud.pigx.common.core.util.ValidGroup; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; -import jakarta.validation.constraints.NotBlank; import java.time.LocalDateTime; /** diff --git a/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/vo/AppUserVO.java b/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/vo/AppUserVO.java index 544228732..14cc34223 100644 --- a/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/vo/AppUserVO.java +++ b/pigx-app-server/pigx-app-server-api/src/main/java/com/pig4cloud/pigx/app/api/vo/AppUserVO.java @@ -1,8 +1,8 @@ package com.pig4cloud.pigx.app.api.vo; import com.pig4cloud.pigx.app.api.entity.AppRole; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveTypeEnum; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java b/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java index a18d55268..55de16875 100644 --- a/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java +++ b/pigx-boot/src/main/java/com/pig4cloud/pigx/bootstrap/PigxBootSecurityServerConfiguration.java @@ -30,7 +30,6 @@ import com.pig4cloud.pigx.common.core.constant.SecurityConstants; import com.pig4cloud.pigx.common.security.component.PermitAllUrlProperties; import com.pig4cloud.pigx.common.security.component.PigxBearerTokenExtractor; import com.pig4cloud.pigx.common.security.component.ResourceAuthExceptionEntryPoint; -import com.pig4cloud.pigx.common.security.handler.SensitiveSkipHandler; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -46,7 +45,6 @@ import org.springframework.security.oauth2.server.authorization.config.annotatio import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; -import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; import org.springframework.security.web.DefaultSecurityFilterChain; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationConverter; @@ -60,104 +58,103 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @RequiredArgsConstructor public class PigxBootSecurityServerConfiguration { - private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint; + private final ResourceAuthExceptionEntryPoint resourceAuthExceptionEntryPoint; - private final OpaqueTokenIntrospector customOpaqueTokenIntrospector; + private final OpaqueTokenIntrospector customOpaqueTokenIntrospector; - private final AuthenticationConverter accessTokenRequestConverter; + private final AuthenticationConverter accessTokenRequestConverter; - private final OAuth2AuthorizationService authorizationService; + private final OAuth2AuthorizationService authorizationService; - private final PigxBearerTokenExtractor pigBearerTokenExtractor; + private final PigxBearerTokenExtractor pigBearerTokenExtractor; - private final PasswordDecoderFilter passwordDecoderFilter; + private final PasswordDecoderFilter passwordDecoderFilter; - private final OAuth2TokenGenerator oAuth2TokenGenerator; + private final OAuth2TokenGenerator oAuth2TokenGenerator; - private final ValidateCodeFilter validateCodeFilter; + private final ValidateCodeFilter validateCodeFilter; - private final PermitAllUrlProperties permitAllUrl; + private final PermitAllUrlProperties permitAllUrl; - @Bean - @Order(Ordered.HIGHEST_PRECEDENCE) - public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, - PigxAuthenticationSuccessEventHandler successEventHandler, - PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { - OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http, + PigxAuthenticationSuccessEventHandler successEventHandler, + PigxAuthenticationFailureEventHandler failureEventHandler) throws Exception { + OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer(); - // 增加验证码过滤器 - http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); - // 增加密码解密过滤器 - http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); - http.addFilterAfter(new SensitiveSkipHandler(), BearerTokenAuthenticationFilter.class); + // 增加验证码过滤器 + http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class); + // 增加密码解密过滤器 + http.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class); - // 认证服务器配置 - http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 - tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter) // 注入自定义的授权认证Converter - .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 - .errorResponseHandler(failureEventHandler);// 登录失败处理器 - }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 - oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 - , Customizer.withDefaults()) - .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); + // 认证服务器配置 + http.with(authorizationServerConfigurer.tokenEndpoint((tokenEndpoint) -> {// 个性化认证授权端点 + tokenEndpoint.accessTokenRequestConverter(accessTokenRequestConverter) // 注入自定义的授权认证Converter + .accessTokenResponseHandler(successEventHandler) // 登录成功处理器 + .errorResponseHandler(failureEventHandler);// 登录失败处理器 + }).clientAuthentication(oAuth2ClientAuthenticationConfigurer -> // 个性化客户端认证 + oAuth2ClientAuthenticationConfigurer.errorResponseHandler(failureEventHandler))// 处理客户端认证异常 + , Customizer.withDefaults()) + .with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 + .authorizationServerSettings( + AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), + Customizer.withDefaults()); - // 资源服务器配置 - AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() - .stream() - .map(AntPathRequestMatcher::new) - .toList() - .toArray(new AntPathRequestMatcher[] {}); + // 资源服务器配置 + AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls() + .stream() + .map(AntPathRequestMatcher::new) + .toList() + .toArray(new AntPathRequestMatcher[]{}); - http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) - .permitAll() - .anyRequest() - .authenticated()) - .oauth2ResourceServer( - oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector)) - .authenticationEntryPoint(resourceAuthExceptionEntryPoint) - .bearerTokenResolver(pigBearerTokenExtractor)) - .exceptionHandling(configurer -> configurer.authenticationEntryPoint(resourceAuthExceptionEntryPoint)) - .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) - .csrf(AbstractHttpConfigurer::disable); + http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) + .permitAll() + .anyRequest() + .authenticated()) + .oauth2ResourceServer( + oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector)) + .authenticationEntryPoint(resourceAuthExceptionEntryPoint) + .bearerTokenResolver(pigBearerTokenExtractor)) + .exceptionHandling(configurer -> configurer.authenticationEntryPoint(resourceAuthExceptionEntryPoint)) + .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + .csrf(AbstractHttpConfigurer::disable); - http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 - .authorizationServerSettings( - AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), - Customizer.withDefaults()); + http.with(authorizationServerConfigurer.authorizationService(authorizationService)// redis存储token的实现 + .authorizationServerSettings( + AuthorizationServerSettings.builder().issuer(SecurityConstants.PIGX_LICENSE).build()), + Customizer.withDefaults()); - DefaultSecurityFilterChain securityFilterChain = http.build(); + DefaultSecurityFilterChain securityFilterChain = http.build(); - // 注入自定义授权模式实现 - addCustomOAuth2GrantAuthenticationProvider(http); - return securityFilterChain; - } + // 注入自定义授权模式实现 + addCustomOAuth2GrantAuthenticationProvider(http); + return securityFilterChain; + } - /** - * 注入授权模式实现提供方 - *

- * 1. 密码模式
- * 2. 短信登录
- */ - @SuppressWarnings("unchecked") - private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) { - AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); - OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class); + /** + * 注入授权模式实现提供方 + *

+ * 1. 密码模式
+ * 2. 短信登录
+ */ + @SuppressWarnings("unchecked") + private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) { + AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); + OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class); - OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider( - authenticationManager, authorizationService, oAuth2TokenGenerator); + OAuth2ResourceOwnerPasswordAuthenticationProvider resourceOwnerPasswordAuthenticationProvider = new OAuth2ResourceOwnerPasswordAuthenticationProvider( + authenticationManager, authorizationService, oAuth2TokenGenerator); - OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider( - authenticationManager, authorizationService, oAuth2TokenGenerator); + OAuth2ResourceOwnerSmsAuthenticationProvider resourceOwnerSmsAuthenticationProvider = new OAuth2ResourceOwnerSmsAuthenticationProvider( + authenticationManager, authorizationService, oAuth2TokenGenerator); - // 处理 UsernamePasswordAuthenticationToken - http.authenticationProvider(new PigxDaoAuthenticationProvider()); - // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken - http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider); - // 处理 OAuth2ResourceOwnerSmsAuthenticationToken - http.authenticationProvider(resourceOwnerSmsAuthenticationProvider); - } + // 处理 UsernamePasswordAuthenticationToken + http.authenticationProvider(new PigxDaoAuthenticationProvider()); + // 处理 OAuth2ResourceOwnerPasswordAuthenticationToken + http.authenticationProvider(resourceOwnerPasswordAuthenticationProvider); + // 处理 OAuth2ResourceOwnerSmsAuthenticationToken + http.authenticationProvider(resourceOwnerSmsAuthenticationProvider); + } } diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index 36fd752c5..a469507c9 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -14,7 +14,7 @@ pigx-common-bom pom ${pigx.version} - pigx 公共版本控制 + pigx 公共版本控制,在此pom定义的依赖,全局业务微服务不需要指定版本。 5.5.0 @@ -111,6 +111,11 @@ pigx-common-security ${pigx.version} + + com.pig4cloud + pigx-common-sensitive + ${pigx.version} + com.pig4cloud pigx-common-sentinel diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSkipContextHolder.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSkipContextHolder.java deleted file mode 100644 index 67f6a9c0a..000000000 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSkipContextHolder.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.pig4cloud.pigx.common.core.sensitive; - -import com.alibaba.ttl.TransmittableThreadLocal; -import lombok.experimental.UtilityClass; - -import java.util.Objects; - -/** - * 脱密跳过ttl - * - * @author lengleng - * @date 2024/6/26 - */ -@UtilityClass -public class SensitiveSkipContextHolder { - - private final ThreadLocal THREAD_LOCAL_SKIP = new TransmittableThreadLocal<>(); - - /** - * 设置是否跳过脱敏 - * - * @param skip 是否跳过 - */ - public void setSkip(Boolean skip) { - THREAD_LOCAL_SKIP.set(skip); - } - - /** - * 获取是否跳过脱敏 - * - * @return 是否跳过 - */ - public Boolean getSkip() { - return Objects.isNull(THREAD_LOCAL_SKIP.get()) ? Boolean.FALSE : THREAD_LOCAL_SKIP.get(); - } - - /** - * 清除 - */ - public void clear() { - THREAD_LOCAL_SKIP.remove(); - } -} diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveTypeEnum.java b/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveTypeEnum.java deleted file mode 100644 index 3ffda7ee0..000000000 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveTypeEnum.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.core.sensitive; - -/** - * 敏感信息枚举类 - * - * @author mayee - * @version v1.0 - **/ -public enum SensitiveTypeEnum { - - /** - * 自定义 - */ - CUSTOMER, - /** - * 用户名, 刘*华, 徐* - */ - CHINESE_NAME, - /** - * 身份证号, 110110********1234 - */ - ID_CARD, - /** - * 座机号, ****1234 - */ - FIXED_PHONE, - /** - * 手机号, 176****1234 - */ - MOBILE_PHONE, - /** - * 地址, 北京******** - */ - ADDRESS, - /** - * 电子邮件, s*****o@xx.com - */ - EMAIL, - /** - * 银行卡, 622202************1234 - */ - BANK_CARD, - /** - * 密码, 永远是 ******, 与长度无关 - */ - PASSWORD, - /** - * 密钥, 【密钥】密钥除了最后三位其他都是***, 与长度无关 - */ - KEY, - /** - * IPV4 类型 113.123.198.176 主机部分打码 113.123.*.123 - */ - IPV4, - - /** - * 中国大陆车牌,包含普通车辆、新能源车辆 - */ - CAR_LICENSE - -} diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java index 88a91266e..ab73caf14 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxResourceServerConfiguration.java @@ -16,7 +16,6 @@ package com.pig4cloud.pigx.common.security.component; -import com.pig4cloud.pigx.common.security.handler.SensitiveSkipHandler; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -28,7 +27,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; -import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -61,9 +59,6 @@ public class PigxResourceServerConfiguration { .toList() .toArray(new AntPathRequestMatcher[]{}); - // 增加输出脱敏的处理 - http.addFilterAfter(new SensitiveSkipHandler(), BearerTokenAuthenticationFilter.class); - http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers) .permitAll() .anyRequest() diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java deleted file mode 100644 index bacdd9eb7..000000000 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/handler/SensitiveSkipHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.pig4cloud.pigx.common.security.handler; - -import com.pig4cloud.pigx.common.core.constant.SecurityConstants; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveSkipContextHolder; -import com.pig4cloud.pigx.common.security.service.PigxUser; -import com.pig4cloud.pigx.common.security.util.SecurityUtils; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.web.filter.OncePerRequestFilter; - -import java.io.IOException; - -/** - * 敏感词跳过的处理器 - * - * @author lengleng - * @date 2024/6/26 - */ -public class SensitiveSkipHandler extends OncePerRequestFilter { - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - PigxUser user = SecurityUtils.getUser(); - - if (user == null) { - filterChain.doFilter(request, response); - return; - } - - try { - if (user.getAuthorities().stream().map(GrantedAuthority::getAuthority) - .toList().contains(SecurityConstants.NO_MASK)) { - SensitiveSkipContextHolder.setSkip(true); - } - filterChain.doFilter(request, response); - } finally { - SensitiveSkipContextHolder.clear(); - } - } -} diff --git a/pigx-common/pigx-common-sensitive/pom.xml b/pigx-common/pigx-common-sensitive/pom.xml new file mode 100644 index 000000000..cab910896 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/pom.xml @@ -0,0 +1,64 @@ + + + + + 4.0.0 + + com.pig4cloud + pigx-common + 5.5.0 + + + pigx-common-sensitive + jar + + pigx 输出脱敏工具类 + + + + + + org.springframework + spring-webmvc + provided + + + cn.hutool + hutool-core + + + cn.hutool + hutool-extra + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework.security + spring-security-core + + + diff --git a/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/SensitiveAutoConfiguration.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/SensitiveAutoConfiguration.java new file mode 100644 index 000000000..5f7665087 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/SensitiveAutoConfiguration.java @@ -0,0 +1,48 @@ +package com.pig4cloud.pigx.common.sensitive; + +import com.pig4cloud.pigx.common.sensitive.core.SensitiveService; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.Objects; + +/** + * 脱敏配置类 + * + * @author lengleng + * @date 2024/6/27 + */ +@AutoConfiguration +@Configuration(proxyBeanMethods = false) +public class SensitiveAutoConfiguration { + /** + * 不脱敏的权限 + */ + public static String NO_MASK = "no_mask"; + + + /** + * 注入默认的脱敏权限判断 + * + * @return SensitiveService + */ + @Bean + @ConditionalOnMissingBean + public SensitiveService sensitiveService() { + return sensitive -> { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (Objects.isNull(authentication)) { + return true; + } + + // 判断角色是否包含 no_mask 的权限 + return authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority) + .noneMatch(s -> s.equals(NO_MASK)); + }; + } +} diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/Sensitive.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/annotation/Sensitive.java similarity index 90% rename from pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/Sensitive.java rename to pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/annotation/Sensitive.java index a78f4422a..68a2719a9 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/Sensitive.java +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/annotation/Sensitive.java @@ -15,10 +15,12 @@ * Author: lengleng (wangiegie@gmail.com) */ -package com.pig4cloud.pigx.common.core.sensitive; +package com.pig4cloud.pigx.common.sensitive.annotation; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveSerialize; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveSerialize.java similarity index 52% rename from pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java rename to pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveSerialize.java index a0e833b4a..a5649d665 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/sensitive/SensitiveSerialize.java +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveSerialize.java @@ -15,18 +15,20 @@ * Author: lengleng (wangiegie@gmail.com) */ -package com.pig4cloud.pigx.common.core.sensitive; +package com.pig4cloud.pigx.common.sensitive.core; -import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; -import com.pig4cloud.pigx.common.core.util.DesensitizedUtils; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.util.Objects; @@ -37,69 +39,32 @@ import java.util.Objects; *

* 脱敏序列化 */ +@Slf4j @NoArgsConstructor @AllArgsConstructor public class SensitiveSerialize extends JsonSerializer implements ContextualSerializer { - private SensitiveTypeEnum type; - - private Integer prefixNoMaskLen; - - private Integer suffixNoMaskLen; - - private String maskStr; + private Sensitive sensitive; @Override public void serialize(final String origin, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException { - // 跳过脱敏 - if (SensitiveSkipContextHolder.getSkip()) { + if (StrUtil.isBlank(origin)) { jsonGenerator.writeString(origin); return; } - switch (type) { - case CHINESE_NAME: - jsonGenerator.writeString(DesensitizedUtils.chineseName(origin)); - break; - case ID_CARD: - jsonGenerator.writeString(DesensitizedUtils.idCardNum(origin)); - break; - case FIXED_PHONE: - jsonGenerator.writeString(DesensitizedUtils.fixedPhone(origin)); - break; - case MOBILE_PHONE: - jsonGenerator.writeString(DesensitizedUtils.mobilePhone(origin)); - break; - case ADDRESS: - jsonGenerator.writeString(DesensitizedUtils.address(origin)); - break; - case EMAIL: - jsonGenerator.writeString(DesensitizedUtils.email(origin)); - break; - case BANK_CARD: - jsonGenerator.writeString(DesensitizedUtils.bankCard(origin)); - break; - case PASSWORD: - jsonGenerator.writeString(DesensitizedUtils.password(origin)); - break; - case KEY: - jsonGenerator.writeString(DesensitizedUtils.key(origin)); - break; - case IPV4: - jsonGenerator.writeString(DesensitizedUtils.ipv4(origin)); - break; - case CAR_LICENSE: - jsonGenerator.writeString(DesensitizedUtil.carLicense(origin)); - break; - case CUSTOMER: - jsonGenerator - .writeString(DesensitizedUtils.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, maskStr)); - break; - default: - throw new IllegalArgumentException("Unknow sensitive type enum " + type); + // 判断是否有可以查看原文 + SensitiveService sensitiveService = SpringUtil.getBean(SensitiveService.class); + if (!sensitiveService.isSensitive(sensitive)) { + jsonGenerator.writeString(origin); + return; } + + // 根据配置注解获取脱敏类型并处理 + String result = sensitive.type().getStrategy().apply(sensitive, origin); + jsonGenerator.writeString(result); } @Override @@ -112,8 +77,8 @@ public class SensitiveSerialize extends JsonSerializer implements Contex sensitive = beanProperty.getContextAnnotation(Sensitive.class); } if (sensitive != null) { - return new SensitiveSerialize(sensitive.type(), sensitive.prefixNoMaskLen(), - sensitive.suffixNoMaskLen(), sensitive.maskStr()); + this.sensitive = sensitive; + return this; } } return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); diff --git a/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveService.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveService.java new file mode 100644 index 000000000..399f9ce35 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveService.java @@ -0,0 +1,16 @@ +package com.pig4cloud.pigx.common.sensitive.core; + +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; + +/** + * 脱敏逻辑增强处理 + * + * @author lengleng + * @date 2024/6/27 + */ +public interface SensitiveService { + /** + * 是否脱敏 + */ + boolean isSensitive(Sensitive sensitive); +} diff --git a/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveStrategyFunction.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveStrategyFunction.java new file mode 100644 index 000000000..528176122 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveStrategyFunction.java @@ -0,0 +1,11 @@ +package com.pig4cloud.pigx.common.sensitive.core; + +/** + * @author lengleng + * @date 2024/6/27 + */ +@FunctionalInterface +public interface SensitiveStrategyFunction { + + R apply(T t, U u); +} diff --git a/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveTypeEnum.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveTypeEnum.java new file mode 100644 index 000000000..4b0b3b0d6 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/core/SensitiveTypeEnum.java @@ -0,0 +1,92 @@ +/* + * 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.sensitive.core; + +import cn.hutool.core.util.DesensitizedUtil; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.util.DesensitizedUtils; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 敏感信息枚举类 + * + * @author mayee + * @version v1.0 + **/ +@RequiredArgsConstructor +public enum SensitiveTypeEnum { + + /** + * 自定义 + */ + CUSTOMER((sensitive, input) -> DesensitizedUtils.desValue(input, sensitive.prefixNoMaskLen(), sensitive.suffixNoMaskLen(), sensitive.maskStr())), + /** + * 用户名, 刘*华, 徐* + */ + CHINESE_NAME((sensitive, input) -> DesensitizedUtils.chineseName(input)), + /** + * 身份证号, 110110********1234 + */ + ID_CARD((sensitive, input) -> DesensitizedUtils.idCardNum(input)), + /** + * 座机号, ****1234 + */ + FIXED_PHONE((sensitive, input) -> DesensitizedUtils.fixedPhone(input)), + /** + * 手机号, 176****1234 + */ + MOBILE_PHONE((sensitive, input) -> DesensitizedUtils.mobilePhone(input)), + /** + * 地址, 北京******** + */ + ADDRESS((sensitive, input) -> DesensitizedUtils.address(input)), + /** + * 电子邮件, s*****o@xx.com + */ + EMAIL((sensitive, input) -> DesensitizedUtils.email(input)), + /** + * 银行卡, 622202************1234 + */ + BANK_CARD((sensitive, input) -> DesensitizedUtils.bankCard(input)), + /** + * 密码, 永远是 ******, 与长度无关 + */ + PASSWORD((sensitive, input) -> DesensitizedUtils.password(input)), + /** + * 密钥, 【密钥】密钥除第一位其他都是***, 与长度无关 + */ + KEY((sensitive, input) -> DesensitizedUtils.key(input)), + /** + * IPV4 类型 113.123.198.176 主机部分打码 113.123.*.123 + */ + IPV4((sensitive, input) -> DesensitizedUtils.ipv4(input)), + + /** + * 中国大陆车牌,包含普通车辆、新能源车辆 + */ + CAR_LICENSE((sensitive, input) -> DesensitizedUtil.carLicense(input)); + + + /** + * 获取脱敏策略 + */ + @Getter + private final SensitiveStrategyFunction strategy; + +} diff --git a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/DesensitizedUtils.java b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/util/DesensitizedUtils.java similarity index 98% rename from pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/DesensitizedUtils.java rename to pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/util/DesensitizedUtils.java index 87665dcd3..6f50ba602 100644 --- a/pigx-common/pigx-common-core/src/main/java/com/pig4cloud/pigx/common/core/util/DesensitizedUtils.java +++ b/pigx-common/pigx-common-sensitive/src/main/java/com/pig4cloud/pigx/common/sensitive/util/DesensitizedUtils.java @@ -15,7 +15,7 @@ * Author: lengleng (wangiegie@gmail.com) */ -package com.pig4cloud.pigx.common.core.util; +package com.pig4cloud.pigx.common.sensitive.util; import cn.hutool.core.util.StrUtil; diff --git a/pigx-common/pigx-common-sensitive/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/pigx-common/pigx-common-sensitive/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..000496c98 --- /dev/null +++ b/pigx-common/pigx-common-sensitive/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.pig4cloud.pigx.common.sensitive.SensitiveAutoConfiguration diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml index 7b95ba065..4dbe58d40 100644 --- a/pigx-common/pom.xml +++ b/pigx-common/pom.xml @@ -49,6 +49,7 @@ pigx-common-oss pigx-common-seata pigx-common-security + pigx-common-sensitive pigx-common-sentinel pigx-common-sequence pigx-common-swagger diff --git a/pigx-upms/pigx-upms-api/pom.xml b/pigx-upms/pigx-upms-api/pom.xml index 3e8c27c51..7f553deb2 100644 --- a/pigx-upms/pigx-upms-api/pom.xml +++ b/pigx-upms/pigx-upms-api/pom.xml @@ -64,5 +64,10 @@ org.javers javers-core + + + com.pig4cloud + pigx-common-sensitive + diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysLog.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysLog.java index dc5fe6371..68f93bba7 100644 --- a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysLog.java +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysLog.java @@ -22,9 +22,9 @@ package com.pig4cloud.pigx.admin.api.entity; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.*; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveTypeEnum; import com.pig4cloud.pigx.common.core.util.TenantTable; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Data; diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSocialDetails.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSocialDetails.java index 156705905..dced0bf44 100755 --- a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSocialDetails.java +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/entity/SysSocialDetails.java @@ -19,14 +19,13 @@ package com.pig4cloud.pigx.admin.api.entity; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; import com.pig4cloud.pigx.common.core.util.TenantTable; import com.pig4cloud.pigx.common.core.util.ValidGroup; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; - -import jakarta.validation.constraints.NotBlank; import lombok.experimental.FieldNameConstants; import java.time.LocalDateTime; @@ -39,6 +38,7 @@ import java.time.LocalDateTime; */ @Data @FieldNameConstants +@TenantTable @Schema(description = "第三方账号信息") @EqualsAndHashCode(callSuper = true) public class SysSocialDetails extends Model { diff --git a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/UserVO.java b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/UserVO.java index 9bead308c..6459556cc 100644 --- a/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/UserVO.java +++ b/pigx-upms/pigx-upms-api/src/main/java/com/pig4cloud/pigx/admin/api/vo/UserVO.java @@ -21,8 +21,8 @@ package com.pig4cloud.pigx.admin.api.vo; import com.pig4cloud.pigx.admin.api.entity.SysPost; import com.pig4cloud.pigx.admin.api.entity.SysRole; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveTypeEnum; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/pigx-visual/pigx-mp-platform/pom.xml b/pigx-visual/pigx-mp-platform/pom.xml index 78a8bddf6..6fa57d89f 100755 --- a/pigx-visual/pigx-mp-platform/pom.xml +++ b/pigx-visual/pigx-mp-platform/pom.xml @@ -76,6 +76,11 @@ com.pig4cloud pigx-common-log + + + com.pig4cloud + pigx-common-sensitive + com.pig4cloud diff --git a/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java b/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java index 8114bbb10..e98317f32 100644 --- a/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java +++ b/pigx-visual/pigx-mp-platform/src/main/java/com/pig4cloud/pigx/mp/entity/WxAccount.java @@ -18,9 +18,9 @@ package com.pig4cloud.pigx.mp.entity; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveTypeEnum; import com.pig4cloud.pigx.common.core.util.TenantTable; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/pigx-visual/pigx-pay-platform/pom.xml b/pigx-visual/pigx-pay-platform/pom.xml index 443f70104..b1b9edb8f 100755 --- a/pigx-visual/pigx-pay-platform/pom.xml +++ b/pigx-visual/pigx-pay-platform/pom.xml @@ -70,10 +70,12 @@ pigx-common-sequence + - cn.hutool - hutool-extra + com.pig4cloud + pigx-common-sensitive + com.pig4cloud diff --git a/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/entity/PayChannel.java b/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/entity/PayChannel.java index e1284c07b..1d40f03a2 100755 --- a/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/entity/PayChannel.java +++ b/pigx-visual/pigx-pay-platform/src/main/java/com/pig4cloud/pigx/pay/entity/PayChannel.java @@ -19,9 +19,9 @@ package com.pig4cloud.pigx.pay.entity; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; -import com.pig4cloud.pigx.common.core.sensitive.Sensitive; -import com.pig4cloud.pigx.common.core.sensitive.SensitiveTypeEnum; import com.pig4cloud.pigx.common.core.util.TenantTable; +import com.pig4cloud.pigx.common.sensitive.annotation.Sensitive; +import com.pig4cloud.pigx.common.sensitive.core.SensitiveTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode;