引言
在实际开发中,我们经常需要处理敏感数据,例如用户的密码、手机号码等,为了防止数据泄露,通常需要对这些数据进行加密或者脱敏处理。本文将介绍如何利用Spring Boot框架实现数据的加密和脱敏,并通过注解、反射和AOP技术来简化代码的编写和维护。
数据加密
实现思路
数据加密是将原始数据按照一定的算法转换成密文,只有经过相应算法的解密操作才能恢复为原始数据。在Spring Boot中,我们可以利用Spring Security提供的加密工具类来实现数据的加密操作。
示例代码
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class DataEncryptUtil {
public static String encryptData(String data) {
// 使用BCryptPasswordEncoder加密数据
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.encode(data);
}
public static boolean verifyData(String raw, String encrypted) {
// 使用BCryptPasswordEncoder校验数据
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.matches(raw, encrypted);
}
}
数据脱敏
实现思路
数据脱敏是将敏感数据按照一定规则进行处理,使得敏感信息无法直接识别,以达到保护数据隐私的目的。在Spring Boot中,我们可以利用注解和AOP技术来实现数据的脱敏操作。
示例代码
1. 定义脱敏注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SensitiveInfo {
SensitiveType type();
int prefix() default 0;
int suffix() default 0;
}
2. 实现脱敏逻辑
import org.springframework.util.StringUtils;
public class DataMaskUtil {
public static String maskData(String data, SensitiveType type, int prefix, int suffix) {
if (StringUtils.isEmpty(data)) {
return data;
}
switch (type) {
case NAME:
return maskName(data, prefix, suffix);
case PHONE_NUMBER:
return maskPhoneNumber(data, prefix, suffix);
// 添加其他敏感信息的脱敏逻辑
default:
return data;
}
}
private static String maskName(String name, int prefix, int suffix) {
if (StringUtils.isEmpty(name)) {
return name;
}
StringBuilder sb = new StringBuilder();
if (prefix > 0) {
sb.append(name, 0, prefix);
}
sb.append("***");
if (suffix > 0 && name.length() > suffix) {
sb.append(name.substring(name.length() - suffix));
} else {
sb.append(name.substring(prefix));
}
return sb.toString();
}
private static String maskPhoneNumber(String phoneNumber, int prefix, int suffix) {
if (StringUtils.isEmpty(phoneNumber)) {
return phoneNumber;
}
StringBuilder sb = new StringBuilder();
if (prefix > 0) {
sb.append(phoneNumber, 0, prefix);
}
sb.append("****");
if (suffix > 0 && phoneNumber.length() > suffix) {
sb.append(phoneNumber.substring(phoneNumber.length() - suffix));
} else {
sb.append(phoneNumber.substring(prefix));
}
return sb.toString();
}
}
3. 实现数据脱敏的切面
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.FieldSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
@Aspect
@Component
public class DataMaskAspect {
@Pointcut("@annotation(com.example.demo.annotation.SensitiveInfo)")
public void dataMaskPointcut() {
}
@Before("dataMaskPointcut()")
public void before(JoinPoint joinPoint) throws IllegalAccessException {
for (Object arg : joinPoint.getArgs()) {
Field[] fields = arg.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SensitiveInfo.class)) {
field.setAccessible(true);
maskFieldValue(arg, field);
}
}
}
}
private void maskFieldValue(Object obj, Field field) throws IllegalAccessException {
SensitiveInfo sensitiveInfo = field.getAnnotation(SensitiveInfo.class);
field.setAccessible(true);
String fieldValue = (String) field.get(obj);
String maskedValue = DataMaskUtil.maskData(fieldValue, sensitiveInfo.type(), sensitiveInfo.prefix(), sensitiveInfo.suffix());
field.set(obj, maskedValue);
}
}
使用示例
1. 定义实体类
import com.example.demo.annotation.SensitiveInfo;
import com.example.demo.annotation.SensitiveType;
public class User {
@SensitiveInfo(type = SensitiveType.NAME, prefix = 1, suffix = 0)
private String name;
@SensitiveInfo(type = SensitiveType.PHONE_NUMBER, prefix = 3, suffix = 4)
private String phoneNumber;
// 省略其他属性和方法
}
2. 测试数据脱敏
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
User user = new User();
user.setName("张三");
user.setPhoneNumber("13812345678");
return user;
}
}
3. 测试结果
请求接口 /users/1
,返回结果如下:
{
"name": "张*",
"phoneNumber": "138****5678"
}
结语
通过上述方式,我们可以简化数据加密和脱敏的代码编写和维护工作,提高开发效率。同时,结合注解、反射和AOP技术,可以灵活地对不同类型的数据进行加密和脱敏处理。当然,根据实际需求,我们还可以扩展更多的脱敏规则,以满足不同场景下的数据保护需求。
本文来自极简博客,作者:智慧探索者,转载请注明原文链接:Spring Boot实现数据加密脱敏:注解 反射 AOP