- 作者:老汪软件
- 发表时间:2024-01-10 02:00
- 浏览量:
一、介绍
业务场景中经常会遇到诸如用户手机号,身份证号,银行卡号,邮箱,地址,密码等等信息,属于敏感信息,需要保存在数据库中。而很多公司会会要求对数据库中的此类数据进行加密存储。
敏感数据脱敏需要处理的两个问题:
查询操作,需要对查询的关键字进行加密,同时也要对从库中查到的数据进行解密插入和更新操作,需要对插入或者更新的数据进行加密,然后保存到数据库 二、解决思路
使用框架提供的来实现在持久层处理数据。
是提供的一个接口,通过实现这个接口,可以实现jdbc类型数据和java类型数据的转换,我们常看到的转、转long等都是自身实现此接口处理的。
因此,可以自己实现一个,满足自己的数据处理需求。
优点:实现也简单,使用方便,整个使用过程只需要对xml代码做修改
三、实现 1. 加解密方法: 这里的加解密方法就直接使用的des加密了。
org.springframework.boot
spring-boot-starter-web
cn.hutool
hutool-all
5.8.15
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.2
mysql
mysql-connector-java
8.0.33
2. 编写自定义的,继承自
package com.zsx.common;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @Description typeHandler加解密处理器 将String类型的字段加密或解密
* @author zhousx
* @Data 2023-10-15 13:02
*/
@Slf4j
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(String.class)
public class CryptoTypeHandler extends BaseTypeHandler {
private final byte[] key = {-26, -70, -29, -99, 73, -82, 91, -50, 79, -77, 59, 104, 2, -36, 50, -22, -39, -15, -57, -89, 81, -99, 42, -89};
private final SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DESede, key);
/*
* 加工入参
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
if (parameter != null) {
//加密
String encryptHex = des.encryptHex(parameter);
log.info("{} ---加密为---> {}", parameter, encryptHex);
ps.setString(i, encryptHex);
}
}
/*
* 根据列名获取返回结果,可在此方法中加工返回值
*/
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String originRes = rs.getString(columnName);
if (originRes != null) {
String res = des.decryptStr(originRes);
log.info("{} ---解密为---> {}", originRes, res);
return res;
}
log.info("结果为空,无需解密");
return null;
}
/*
* 根据列下标获取返回结果,可在此方法中加工返回值
*/
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String originRes = rs.getString(columnIndex);
if (originRes != null) {
String res = des.decryptStr(originRes);
log.info("{} ---解密为---> {}", originRes, res);
return res;
}
log.info("结果为空,无需解密");
return null;
}
/*
* 根据列下标获取返回结果(存储过程),可在此方法中加工返回值
*/
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String originRes = cs.getString(columnIndex);
if (originRes != null) {
String res = des.decryptStr(originRes);
log.info("{} ---解密为---> {}", originRes, res);
return res;
}
log.info("结果为空,无需解密");
return null;
}
}
3. 注册自定义的到
.yml
server:
port: 8082
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=true
username: root
password: 123456
mybatis:
# 编写好的TypeHandler需要注册到mybatis中
type-handlers-package: com.zsx.cryptotypehandler.common
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4. 使用
实体类 User.java
package com.zsx.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String phone;
}
dao层 .java
package com.zsx.dao;
import com.zsx.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* userMapper
*/
@Mapper
public interface IUserDao {
int insertEncrypt(User user);
List findByName(User user);
List findByPhone(User user);
List findByPhone2(String phone);
}
xml文件 .xml
insert into user (id, name, phone)
values (#{id}, #{name}, #{phone,typeHandler=com.zsx.common.CryptoTypeHandler})
最后的测试代码 st.java
package com.zsx;
import com.zsx.dao.IUserDao;
import com.zsx.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class EncryptTypeHandlerTest {
@Autowired
private IUserDao userDao;
@Test
public void testInsert(){
User user = new User();
user.setPhone("11112222333");
user.setName("zsx");
int result = userDao.insertEncrypt(user);
System.out.println(result);
}
@Test
public void testSelectByName(){
User user = new User();
user.setName("zsx");
List userList = userDao.findByName(user);
System.out.println(userList.toString());
}
@Test
public void testSelectByPhone(){
User user = new User();
user.setPhone("11112222333");
List userList = userDao.findByPhone(user);
System.out.println(userList.toString());
}
@Test
public void testSelectByPhone2(){
List userList = userDao.findByPhone2("11112222333");
System.out.println(userList.toString());
}
}
项目结构如下
需要注意:
sql查询的结果,必须要使用 映射,否则就不能完成结果字段的自动解密