进行一个简单的脱敏实际业务中可能会考虑list map等
@Desensitization:标记到需要脱敏的接口上
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Desensitization {
}
@FiledDesensitization:标记到实体属性上
//作用域 作用于方法和类上
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented //表示把注解生成在Javadoc中
public @interface FiledDesensitization {
//默认为身份证号码脱敏
MaskingTypeEnum type() default MaskingTypeEnum.ID_CARD;
}
MaskingTypeEnum 表示脱敏的类型 枚举
public enum MaskingTypeEnum {
/*身份证号码*/
ID_CARD,
/*手机号码*/
PHONE,
/*地址*/
EMAIL,
/*姓名*/
NAME
}
脱敏的类型 如(对idcard进行脱敏身份证):
@ApiModel(value = "TODO")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
@ApiModelProperty(value = "")
private Integer id;
@ApiModelProperty(value = "")
private String username;
@ApiModelProperty(value = "")
@FiledDesensitization(type = MaskingTypeEnum.ID_CARD)
private String idcard;
@ApiModelProperty(value = "")
private String telephon;
@ApiModelProperty(value = "")
private String email;
@ApiModelProperty(value = "")
private String password;
}
util
@Slf4j
public final class SensitiveInfoUtils {
/**
* [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
*
* @param
* @return
*/
public static String chineseName(String fullName) {
if (StringUtils.isBlank(fullName)) {
return "";
}
String name = StringUtils.left(fullName, 1);
return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
}
/**
* [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
*
* @param familyName
* @param givenName
* @return
*/
public static String chineseName(String familyName, String givenName) {
if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
return "";
}
return chineseName(familyName + givenName);
}
/**
* [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
*
* @param id
* @return
*/
public static String idCardNum(String id) {
if (StringUtils.isBlank(id)) {
return "";
}
String num = StringUtils.right(id, 4);
return StringUtils.leftPad(num, StringUtils.length(id), "*");
}
/**
* [固定电话] 后四位,其他隐藏<例子:****1234>
*
* @param num
* @return
*/
public static String fixedPhone(String num) {
if (StringUtils.isBlank(num)) {
return "";
}
return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
}
/**
* [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
*
* @param num
* @return
*/
public static String mobilePhone(String num) {
if (StringUtils.isBlank(num)) {
return "";
}
return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), "***"));
}
/**
* [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
*
* @param address
* @param sensitiveSize 敏感信息长度
* @return
*/
public static String address(String address, int sensitiveSize) {
if (StringUtils.isBlank(address)) {
return "";
}
int length = StringUtils.length(address);
return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
}
/**
* [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
*
* @param email
* @return
*/
public static String email(String email) {
if (StringUtils.isBlank(email)) {
return "";
}
int index = StringUtils.indexOf(email, "@");
if (index <= 1)
return email;
else
return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
}
/**
* [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
*
* @param cardNum
* @return
*/
public static String bankCard(String cardNum) {
if (StringUtils.isBlank(cardNum)) {
return "";
}
return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
}
/**
* [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
*
* @param code
* @return
*/
public static String cnapsCode(String code) {
if (StringUtils.isBlank(code)) {
return "";
}
return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");
}
}
切面
@Component
@Aspect
public class DesensitizationAspect {
@Around("@annotation(Desensitization)")
public Object doAnnotation(ProceedingJoinPoint pjp) throws Throwable {
System.out.print("===方法执行前===");
Object proceed = pjp.proceed();
//如果返回的类型是List
if ("java.util.ArrayList".equals(proceed.getClass().getName())) {
List listResult = new ArrayList();
List<?> list = (List) proceed;
for (int i = 0; i < list.size(); i++) {
Class<?> aClass = list.get(i).getClass();
Field[] declaredFields1 = aClass.getDeclaredFields();
for (Field field : declaredFields1) {
if (field.isAnnotationPresent(FiledDesensitization.class)) {
//setAccessible这行代码把对象上的私有字段为可以设置
field.setAccessible(true);
//如果属性值为null
if (field.get(list.get(i)) == null) {
break;
}
String value = field.get(list.get(i)).toString();
FiledDesensitization annotation = field.getAnnotation(FiledDesensitization.class);
MaskingTypeEnum type = annotation.type();
switch (type) {
case ID_CARD:
field.set(list.get(i), SensitiveInfoUtils.idCardNum(value));
break;
case NAME:
field.set(list.get(i), SensitiveInfoUtils.chineseName(value));
case PHONE:
field.set(list.get(i), SensitiveInfoUtils.mobilePhone(value));
case EMAIL:
field.set(list.get(i), SensitiveInfoUtils.email(value));
break;
}
}
}
listResult.add(list.get(i));
}
return listResult;
}
//如果返回的是单个实体
Class<?> aClass = proceed.getClass();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (declaredField.isAnnotationPresent(FiledDesensitization.class)) {
//setAccessible这行代码把对象上的字段设置为public访问属性.
declaredField.setAccessible(true);
if (declaredField.get(proceed) == null) {
break;
}
String value = declaredField.get(proceed).toString();
FiledDesensitization annotation = declaredField.getAnnotation(FiledDesensitization.class);
MaskingTypeEnum type = annotation.type();
switch (type) {
case ID_CARD:
declaredField.set(proceed, SensitiveInfoUtils.idCardNum(value));
break;
case NAME:
declaredField.set(proceed, SensitiveInfoUtils.chineseName(value));
case PHONE:
declaredField.set(proceed, SensitiveInfoUtils.mobilePhone(value));
case EMAIL:
declaredField.set(proceed, SensitiveInfoUtils.email(value));
break;
}
}
}
return proceed;
}
}
contoller
@RestController
public class UserContoller {
@Autowired
private UserMapper userMapper;
@Desensitization
@GetMapping("/test")
public User test(){
User user = userMapper.selectByPrimaryKey(1L);
return user;
}
@Desensitization
@GetMapping("/test1")
public List<User> test1() {
User user = new User();
user.setIdcard("43252219920724557");
User user1 = new User();
user1.setIdcard("43252219920724557");
User user2 = new User();
user2.setIdcard("43252219920724557");
User user3 = new User();
user3.setIdcard("43252219920724557");
List<User> list = new ArrayList();
list.add(user);
list.add(user1);
list.add(user2);
list.add(user3);
return list;
}
}
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
application.yml
server:
port: 3333
spring:
profiles:
active: data
application:
name: boke-service
cloud:
alibaba:
seata:
# 自定义事务组名称需要与seata-server中的对应
tx-service-group: fsp_tx_group
nacos:
discovery: #Nacos注册中心地址
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
feign:
hystrix:
enabled: true
management:
endpoints:
web:
exposure:
include: "*"
logging:
level:
io:
seata: info
application-data.yml
spring:
datasource:
#当前数据源操作类型
type: com.alibaba.druid.pool.DruidDataSource
#mysql驱动包
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/boke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: zz123456
mybatis:
mapperLocations: classpath:mapping/*.xml
#所有entity别名类所在包
type-aliases-package: com.atguigu.huawei.dao
pom
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-seataartifactId>
<exclusions>
<exclusion>
<artifactId>seata-allartifactId>
<groupId>io.seatagroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>io.seatagroupId>
<artifactId>seata-allartifactId>
<version>0.9.0version>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.8.0version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.8.0version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-staticdocsartifactId>
<version>2.5.0version>
dependency>
dependencies>
父pom
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.atgui.huawei.groupId>
<artifactId>bokeartifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<modules>
<module>spring-alibaba-bokemodule>
modules>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<junit.version>4.12junit.version>
<log4j.version>1.2.17log4j.version>
<lombok.version>1.16.18lombok.version>
<mysql.version>8.0.18mysql.version>
<druid.version>1.1.21druid.version>
<mybatis.spring.boot.version>1.3.0mybatis.spring.boot.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.SR1version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis.spring.boot.version}version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
dependencies>
dependencyManagement>
<build>
build>
project>