背景
mybatis中四大组件的作用,下面开发的插件拦截器会使用
四大组件Executor、StatementHandler、ParameterHandler、ResultSetHandler
需求
1、根据脱敏规则进行查询数据,显示的时候进行展示脱敏
2、根据脱敏规则进行查询数据,将脱敏后的数据批量更新回数据库,进行脱敏存储
数据
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80026 (8.0.26)
Source Host : localhost:3306
Source Schema : mp
Target Server Type : MySQL
Target Server Version : 80026 (8.0.26)
File Encoding : 65001
Date: 18/08/2024 13:44:24
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
`password` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
`phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '注册手机号',
`info` json NOT NULL COMMENT '详细信息',
`status` int NULL DEFAULT 1 COMMENT '使用状态(1正常 2冻结)',
`balance` int NULL DEFAULT NULL COMMENT '账户余额',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `username`(`username` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = COMPACT;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'Jack', 'D5F3C4C80A651CFE876DA231061FA871', '13900112224', '{\"age\": 20, \"intro\": \"佛系青年\", \"gender\": \"male\"}', 1, 1600, '2023-05-19 20:50:21', '2024-08-18 13:43:05');
INSERT INTO `user` VALUES (2, 'Rose', 'D5F3C4C80A651CFE876DA231061FA871', '13900112223', '{\"age\": 19, \"intro\": \"青涩少女\", \"gender\": \"female\"}', 1, 600, '2023-05-19 21:00:23', '2024-08-18 13:43:09');
INSERT INTO `user` VALUES (3, 'Hope', 'D5F3C4C80A651CFE876DA231061FA871', '13900112222', '{\"age\": 25, \"intro\": \"上进青年\", \"gender\": \"male\"}', 1, 100000, '2023-06-19 22:37:44', '2024-08-18 13:43:12');
INSERT INTO `user` VALUES (4, 'Toomas', 'D5F3C4C80A651CFE876DA231061FA871', '17701265258', '{\"age\": 29, \"intro\": \"伏地魔\", \"gender\": \"male\"}', 1, 800, '2023-06-19 23:44:45', '2024-08-18 13:43:27');
SET FOREIGN_KEY_CHECKS = 1;
具体实现
1、定义脱敏规则
mybatis:
interceptors:
# 是否开启拦截
enabled: true
desensitization:
# 是否进行脱敏
enabled: true
rule:
# 脱敏模式
- schema: MP
# 是否全模式脱敏
allSchema: true
# 单模式脱敏规则
schemaRule:
# 模式下需要脱敏的表
- tableName: USER
# 模式下需要脱敏的表的主键字段
keyColumn: id
# 具体表的脱敏规则
tableRule:
# 具体列的脱敏规则
- column: username
columnRule:
# 隐藏脱敏,*代替
ruleType: hide
startIndex: 1
endIndex: 2
- column: password
columnRule:
# 密码aes加密脱敏
ruleType: aes
# 全模式脱敏规则
allTableRule:
- column: username
columnRule:
ruleType: hide
startIndex: 1
endIndex: 2
- column: password
columnRule:
# 密码aes加密脱敏
ruleType: aes
2、配置类
/**
* @author code
* @version 1.0
* @Date 2024/8/16 13:35
* @Description ${DESCRIPTION}
*/
@Data
@Component
@ConfigurationProperties(prefix = "desensitization")
public class DesensitizationConfig {
private String enabled = "false";
private List<DesensitizationBaseRule> rule;
}
/**
* @author code
* @version 1.0
* @Date 2024/8/16 13:37
* @Description 脱敏规则
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class DesensitizationBaseRule implements Serializable {
private static final long serialVersionUID = 1L;
private String schema = "schema";
private String allSchema = "false";
private List<DesensitizationSchemaRule> schemaRule = new ArrayList<>();
private List<DesensitizationTableRule> allTableRule = new ArrayList<>();
}
/**
* @author code
* @version 1.0
* @Date 2024/8/16 13:41
* @Description ${DESCRIPTION}
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class DesensitizationSchemaRule implements Serializable {
private static final long serialVersionUID = 1L;
private String tableName = "table";
private String keyColumn = "id";
private List<DesensitizationTableRule> tableRule;
}
/**
* @author code
* @version 1.0
* @Date 2024/8/16 13:46
* @Description ${DESCRIPTION}
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class DesensitizationTableRule implements Serializable {
private static final long serialVersionUID = 1L;
private String column = "name";
private DesensitizationMaskRule columnRule;
}
/**
* @author code
* @version 1.0
* @Date 2024/8/16 13:50
* @Description ${DESCRIPTION}
*/
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class DesensitizationMaskRule implements Serializable {
private static final long serialVersionUID = 1L;
private String ruleType = "hide";
private int startIndex = 1;
private int endIndex = 2;
}
3、拦截器
/**
* @author code
* @version 1.0
* @Date 2024/8/13 9:54
* @Description ${DESCRIPTION}
*/
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {
Connection.class, Integer.class})
})
@Slf4j
public class SqlQueryInterceptor implements Interceptor {
private static final Pattern TABLE_NAME_PATTERN = Pattern.compile("(FROM|UPDATE)\\s+([\\w\\._]+)");
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
// 获取连接对象
Connection connection = (Connection) invocation.getArgs()[0];
// 获取数据库名称
String databaseName = connection.getCatalog();
log.info("----------当前数据库名:{}", databaseName);
Object parameterObject = statementHandler.getParameterHandler().getParameterObject();
JSONObject paramObject = JSONObject.parseObject(JSON.toJSONString(parameterObject));
BoundSql boundSql = statementHandler.getBoundSql();
//统一转大写
String tableNameSql = boundSql.getSql().toUpperCase();
//获取表名
String tableNa