赞
踩
目前官方文档脱敏部分给出的加密算法的配置都是基于内置的MD5和AES,有很多同学想要自定义加密算法并配置,但是不知道怎么做。可以参考以下实现过程及思路
注意
以下代码使用的ShardingSphere版本为4.1.1
关于数据脱敏详细的文档可参考官网数据脱敏部分
这里采用SHA256的加密算法,由于SHA256加密是不可逆的。所以解密方法只返回密文
@Getter @Setter public final class Sha256Encryptor implements Encryptor { private Properties properties = new Properties(); @Override public void init() { } @Override public String encrypt(final Object plaintext) { if (null == plaintext) { return null; } return DigestUtils.sha256Hex(String.valueOf(plaintext)); } @Override public Object decrypt(final String ciphertext) { return ciphertext; } @Override public String getType() { return "SHA256"; } }
这里对于要脱敏的字段进行配置,这里使用了两种加密策略,对于info字段采用默认的MD5加密,对于name字段采用自定义的SHA256加密
sharding: # 数据脱敏规则配置---start encrypt-rule: encryptors: encryptor_sha256: # 加密、解密器的名字,内置的为MD5,aes. # 可以自定义,实现 # com.example.mybatis.demomybatis.shardingsphere.encrypt # 或者 # org.apache.shardingsphere.encrypt.strategy.spi.QueryAssistedEncryptor # 这两个接口即可 type: SHA256 encryptor_MD5: type: md5 tables: # 数据库,对应上面分片的tables user: columns: # 逻辑列,就是写SQL里面的列,因为实体类的名字和数据库的加密列一致,所以这里都是name name: # 密文列,用来存储密文数据 cipherColumn: name # 加密器名字 encryptor: encryptor_sha256 other_info: cipherColumn: info encryptor: encryptor_MD5 # 数据脱敏规则配置---end
配置完成之后,便去启动,此时启动报错,报错提示
Invalid `org.apache.shardingsphere.encrypt.strategy.spi.Encryptor` SPI type `SHA256`.
可以看到,是由于集合为空抛出的异常,那么这个集合是从哪来的?
进入loadTypeBasedServices(type)方法中,这个方法里只做了一件事,获取当前classtype的集合,并在集合中查找当前type(就是配置的SHA256)
可以看到,最终返回的集合里确实没有自定义的加密器,上面一行可以看到,result的最终结果都来自SERVICE_MAP中,那么说明自定义的加密策略并没有在这个map中
map里确实是没有
看来是在启动的时候没有把自定义的加密策略放到这个map里去造成的,通过debug对这个SERVICE_MAP进行watch发现,这个map是在
在register这里加入的,看到这里的注释就明白了,官方是通过SPI方式将各个功能通过插件的方式加入整个框架之中。这一点官方文档也有说。这里注册加密策略。可以看到,registerServiceClass这个方法往SERVICE_MAP中添加的元素。直接取决于ServiceLoader.load(srevice)这个方法
进入ServiceLoader.load
该方法是java内置的spi机制
顺着断点进去,看到reload好像也没发现什么,那就先看一下这个类是干嘛的,于是首先在注释中找到了答案
注释的前两段对servie-provider进行了详细的描述,关键在于第三部分,注释中明确指出了接入service-provider的说明。
即:在项目的resource目录下,新增配置文件,配置文件位于resource/META-INF/services下,配置文件的名字就是对外提供实现拓展服务的全路径名字,官方文档中加密策略对外提供的service的是Encryptor这个接口。配置文件里的内容就是实现了官方接口的类的全路径。于是看到这里,赶紧去配置一下
后来发现,其实也没有好好看注释,在reload方法中注释表明了,最后会iterator,而最终的路径,以及路径里的内容也是在这里获得的
ServiceLoader是java.util包下的一个工具类,JDK8官方文档说明和其他博主说明
配置文件名字为:org.apache.shardingsphere.encrypt.strategy.spi.Encryptor
接口名字的完全限定名
配置文件里的内容,放入自定义的加密策略的类的全路径,和要使用官方内置的加密策略的类的全路径
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256Encryptor
org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256RandomEncryptor
请求接口,通过debug自定义加密策略加解密方法、控制台打印SQL、数据库查看最终生成的数据、单元测试等手段验证了加密策略生效
再回头看看ShardingSphere在配置了加密策略的时候,究竟干了什么
ShardingSphere在生成数据源的时候会为数据源配置具体的ShardingRule
方法详情见org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory#createDataSource
在ShardingRule中会根据配置生成对应的加密策略,以及配置加密策略对应的加密算法
方法详情见org.apache.shardingsphere.core.rule.ShardingRule#createEncryptRule
具体读取配置文件,以及配置自定义的加密策略是在生成EncryptRule构造方法中的initEncryptors中
方法详情见org.apache.shardingsphere.encrypt.rule.EncryptRule#initEncryptors
这个方法的工作只有两步
在进行数据库操作时,根据配置的加密策略进行加密
至于QueryAssistedEncryptor的应用场景,请阅读官方文档数据脱敏部分
@Getter @Setter public final class Sha256RandomEncryptor implements QueryAssistedEncryptor { private Properties properties = new Properties(); @Override public String queryAssistedEncrypt(final String plaintext) { if (null == plaintext) { return null; } // 原始字符串 return DigestUtils.sha256Hex(String.valueOf(plaintext)); } @Override public void init() { } @Override public String encrypt(final Object plaintext) { if (null == plaintext) { return null; } // 原始字符串+变动因子 byte[] bytes = LocalDateTime.now().toString().getBytes(); HMac hMac = new HMac(HmacAlgorithm.HmacSHA256, bytes); return hMac.digestHex(String.valueOf(plaintext)); } @Override public Object decrypt(final String ciphertext) { return ciphertext; } @Override public String getType() { return "SHA256_RANDOM"; } }
以当前时间戳作为变动因子,或者随机字符串也可以,对于密文列,采用HMac加密,对于查询辅助列,则使用普通的SHA256加密
数据表新增same_data子段
sharding: encrypt-rule: encryptors: encryptor_MD5: type: md5 encryptor_sha256random: type: SHA256_RANDOM tables: # 数据库,对应上面分片的tables user: columns: # 逻辑列,就是写SQL里面的列,因为实体类的名字和数据库的加密列一致,所以这里都是name name: # 密文列,用来存储密文数据 cipherColumn: name # 加密器名字 encryptor: encryptor_sha256random # 辅助查询列 assistedQueryColumn: same_data other_info: cipherColumn: info encryptor: encryptor_MD5
在org.apache.shardingsphere.encrypt.strategy.spi.Encryptor文件中配置自定义加密策略
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256Encryptor
org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
com.example.mybatis.demomybatis.shardingsphere.encrypt.Sha256RandomEncryptor
请求接口,通过debug自定义加密策略加解密方法、控制台打印SQL、数据库查看最终生成的数据、单元测试等手段验证了加密策略生效
可以看到数据库里的数据
对于name这个密文列,由于使用了自定义的加密策略,因为变动因子的原因,所以即使名字相同数据库里的存储也是不同的,而两条记录的same_data是一样的。对于没有变动因子的MD5加密策略,则info加密之后的存储信息也是一样的
通过name去数据库进行查询,即使密文列不相同,但是由于辅助查询列的存在,ShardingSphere能够准确的查出数据
通过打印SQL发现,辅助查询列是新增数据的时候,ShardingSphere根据我们的加密策略以及配置的辅助查询的字段默认插入进去的,改写的SQL如下
ShardingSphere自动帮我们添加了辅助查询列
以上示例代码已经放到GitHub上,如需,请自取。地址
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。