mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 04:39:00 +08:00
✨ 新增 pigx-common-sensitive 脱敏模块
(cherry picked from commit 39899b1e8ff25ca1ac3708086c1ddb677fb56541)
This commit is contained in:
1 parent
aba51bbdb8
commit
e96eaa2179
27 files changed
+374
-323
No files matched your search
@@ -33,5 +33,10 @@
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-excel</artifactId>
|
||||
</dependency>
|
||||
<!-- 脱敏工具类-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+2
-2
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
+78
-81
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入授权模式实现提供方
|
||||
* <p>
|
||||
* 1. 密码模式 </br>
|
||||
* 2. 短信登录 </br>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http) {
|
||||
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
||||
OAuth2AuthorizationService authorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
|
||||
/**
|
||||
* 注入授权模式实现提供方
|
||||
* <p>
|
||||
* 1. 密码模式 </br>
|
||||
* 2. 短信登录 </br>
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<artifactId>pigx-common-bom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>${pigx.version}</version>
|
||||
<description>pigx 公共版本控制</description>
|
||||
<description>pigx 公共版本控制,在此pom定义的依赖,全局业务微服务不需要指定版本。</description>
|
||||
|
||||
<properties>
|
||||
<pigx.version>5.5.0</pigx.version>
|
||||
@@ -111,6 +111,11 @@
|
||||
<artifactId>pigx-common-security</artifactId>
|
||||
<version>${pigx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
<version>${pigx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sentinel</artifactId>
|
||||
|
||||
-43
@@ -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<Boolean> 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();
|
||||
}
|
||||
}
|
||||
-78
@@ -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
|
||||
|
||||
}
|
||||
-5
@@ -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()
|
||||
|
||||
-42
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~
|
||||
~ 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)
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common</artifactId>
|
||||
<version>5.5.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>pigx 输出脱敏工具类</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!--mvc 相关配置-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+48
@@ -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));
|
||||
};
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -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;
|
||||
+19
-54
@@ -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;
|
||||
* <p>
|
||||
* 脱敏序列化
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SensitiveSerialize extends JsonSerializer<String> 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<String> 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);
|
||||
+16
@@ -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);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.pig4cloud.pigx.common.sensitive.core;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2024/6/27
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SensitiveStrategyFunction<T, U, R> {
|
||||
|
||||
R apply(T t, U u);
|
||||
}
|
||||
+92
@@ -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<Sensitive, String, String> strategy;
|
||||
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
com.pig4cloud.pigx.common.sensitive.SensitiveAutoConfiguration
|
||||
@@ -49,6 +49,7 @@
|
||||
<module>pigx-common-oss</module>
|
||||
<module>pigx-common-seata</module>
|
||||
<module>pigx-common-security</module>
|
||||
<module>pigx-common-sensitive</module>
|
||||
<module>pigx-common-sentinel</module>
|
||||
<module>pigx-common-sequence</module>
|
||||
<module>pigx-common-swagger</module>
|
||||
|
||||
@@ -64,5 +64,10 @@
|
||||
<groupId>org.javers</groupId>
|
||||
<artifactId>javers-core</artifactId>
|
||||
</dependency>
|
||||
<!-- 脱敏工具类-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+3
-3
@@ -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<SysSocialDetails> {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -76,6 +76,11 @@
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-log</artifactId>
|
||||
</dependency>
|
||||
<!--必备:脱敏工具类-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
<!-- sentinel-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
@@ -70,10 +70,12 @@
|
||||
<artifactId>pigx-common-sequence</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--必备:脱敏工具类-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--灰度支持-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user