coderj的博客

talk is cheap show me the code

0%

ShardingSphere mysql meta data加载问题复盘

背景

为响应国家 《数据安全法》的要求,我司数据安全部门要求各个业务部门将现存所有 mysql 表中敏感字段加密存储。而我所负责的系统模块有 10 几张表分布在 3 ~ 4 个微服务中,因此我想设计一个通用的改动最少方法对这些表字段加密。

1.0 版本设计

因我司大部分项目使用的是 mybatis 或者 mybatis-plus ORM 框架,所以 1.0 版本的设计是使用 mybatis 拦截器 interceptor 做数据的加密和解密。

遇到的问题

mybatis generator 可以生成多种方式的 mapper
xxxExample 格式的查询语句
dynamic sql 格式的查询

解决方案

1.1 版本设计

mybatis 拦截器 + jsqlparser

2.0 版本设计

因 1.0 版本和 1.1 版本设计的各种问题,需要一种通用性更强的设计,经过各种百度先后确定使用 apache shardingsphere-jdbc encrypt 模块来做加解密。

遇到的问题

mysql schema meta 无法获取

ShardingSphereResultSet

EncryptMergedResult:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public final class EncryptMergedResult implements MergedResult {

private final EncryptAlgorithmMetaData metaData;

private final MergedResult mergedResult;

@Override
public boolean next() throws SQLException {
return mergedResult.next();
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public Object getValue(final int columnIndex, final Class<?> type) throws SQLException {
Optional<EncryptContext> encryptContext = metaData.findEncryptContext(columnIndex);
if (!encryptContext.isPresent() || !metaData.isQueryWithCipherColumn(encryptContext.get().getTableName(), encryptContext.get().getColumnName())) {
return mergedResult.getValue(columnIndex, type);
}
Optional<EncryptAlgorithm> encryptAlgorithm = metaData.findEncryptor(encryptContext.get().getTableName(), encryptContext.get().getColumnName());
if (!encryptAlgorithm.isPresent()) {
return mergedResult.getValue(columnIndex, type);
}
Object cipherValue = mergedResult.getValue(columnIndex, Object.class);
return null == cipherValue ? null : encryptAlgorithm.get().decrypt(cipherValue, encryptContext.get());
}

@Override
public Object getCalendarValue(final int columnIndex, final Class<?> type, final Calendar calendar) throws SQLException {
return mergedResult.getCalendarValue(columnIndex, type, calendar);
}

@Override
public InputStream getInputStream(final int columnIndex, final String type) throws SQLException {
return mergedResult.getInputStream(columnIndex, type);
}

@Override
public boolean wasNull() throws SQLException {
return mergedResult.wasNull();
}
}

解决方案

拉取 shardingsphere 源码 修改/编译/打包/发私服

总结