如题,我们客户有要求 敏感字段 入库要加密处理。以及有权限的人登录后还可查看原文。看到反馈区有社友使用数据库的函数加密,感觉不妥。1 是不方便 操作,2 是数据库的函数处理一般都比较耗费 cpu。所以放到 Java 这边来处理感觉是更好的。
废话不多说,上 石马 !
工具类:
/**
* 对称加密工具
* @author dufuzhong
*/
@SuppressWarnings("unused")
public class AesStrKit {
private static String aesKey;
private static String getAesKey() {
if (aesKey == null){
//配置文件获取秘钥 PropKit工具
aesKey = AppConfig.get("aesKey");
Objects.requireNonNull(aesKey, "配置文件 aesKey 未配置秘钥");
}
return aesKey;
}
public static void main(String[] args) {
/* 放开注释 执行 main方法 可以获得一个秘钥
aesKey = AesKit.genAesKey();
LogKit.info("获取一个秘钥,注意需要自己复制下面内容,写入到配置文件中才可以更新:");
LogKit.info("aesKey=" + aesKey);
*/
//修改 表名 与 字段名 后 执行 main方法 即可
//启动数据库连接池与Db配置插件
// AppConfig.plugins(() -> {
// dbEncode("表名1", "phone", "idCard", "email", "bankCard");
// dbEncode("表名2", "xxx");
// });
}
/**
* 数据库旧数据 明文 转换为 密文
* @param table 需要处理的表
* @param columns 需要处理的字段
*/
public static void dbEncode(String table, String... columns) {
Kv kv = Kv.by("table", table).set("columns", columns);
//数据库字段长度修改为 varchar255, 一般业务够用, 看业务情况自己加
String sqlModify = "ALTER TABLE #(table) " +
"#for(x : columns) #if(!for.first),#end MODIFY COLUMN `#(x)` varchar(255) #end ";
Db.templateByString(sqlModify, kv).update();
LogKit.info("数据库字段长度修改为255");
String sqlFind = "select id #for(x : columns), #(x) #end from #(table)";
Db.templateByString(sqlFind, kv).each(record -> {
for (String column : columns) {
String v = record.getStr(column);
if (StrKit.notBlank(v) && v.length() < 30){
LogKit.debug(v);
record.set(column, encode(v));
}
}
Db.update(table, record);
return true;
});
LogKit.info(table + "》dbEncode执行完成");
}
/**
* 加密
* @param content 明文
* @return 密文
*/
public static String encode(String content) {
if (StrKit.isBlank(content)){
return content;
}
return Base64Kit.encode(AesKit.encrypt(content, getAesKey()));
}
/**
* 解密
* @param encode 密文
* @return 明文
*/
public static String decrypt(String encode) {
if (StrKit.isBlank(encode)){
return encode;
}
try {
return AesKit.decryptToStr(Base64Kit.decode(encode), getAesKey());
}catch (RuntimeException ignored){
//LogKit.error("解密异常:" + encode);
//解密异常 目前不让报错处理,页面正常显示其他内容
return encode;
}
}
}工具相对简单。AesKey 是放在配置文件里面的。
在需要入库加密的字段前 record.set(column, AesStrKit.encode(v)); 调用一下即可,
上面有一个数据库旧数据 明文 转换为 密文的处理工具就是这样。
密文展示为原文也是一样,调用一下解密即可。
如果没有处理历史数据的场景,可以把 dbEncode 方法移除即可,下面代码也不用参考了。
其中有用到一个 AppConfig 类,是JFinalConfig子类,我这边部分代码贴一下(大家自己项目的都不一样):
public class AppConfig extends JFinalConfig {
private static Prop p = null;
public static Prop p() {
if (p == null){
p = PropKit.append("apiConfig.txt").appendIfExists("apiConfig_pro.txt");
//设置开发模式
JFinal.me().getConstants().setDevMode(p.getBoolean("devMode"));
}
return p;
}
public static String get(String key){
return p().get(key);
}
//...省略 JF 配置代码
/**
* 独立启动插件, 如启动数据库等, 使用完后自动关闭
*/
public static void plugins(Runnable runnable){
PluginsPlugin p = new PluginsPlugin();
new AppConfig().configPlugin(p.getPlugins());
p.run(runnable);
}
}经常用到需要独立启动的测试类,所以对Plugins打包了一下:
import com.jfinal.config.Plugins;
import com.jfinal.plugin.IPlugin;
import java.util.List;
public class PluginsPlugin implements IPlugin {
private Plugins ps = new Plugins();
public static PluginsPlugin of(IPlugin... plugins){
PluginsPlugin pp = new PluginsPlugin();
if (plugins != null) {
for (IPlugin plugin : plugins) {
pp.add(plugin);
}
}
return pp;
}
public Plugins getPlugins() {
return ps;
}
public PluginsPlugin add(IPlugin plugin) {
ps.add(plugin);
return this;
}
public void run(Runnable runnable){
this.start();
try{
runnable.run();
}finally {
this.stop();
}
}
@Override
public boolean start() {
for (IPlugin p : ps.getPluginList()) {
p.start();
}
return true;
}
@Override
public boolean stop() {
List<IPlugin> list = ps.getPluginList();
for (int i = list.size() - 1; i >= 0; i--) {
list.get(i).stop();
}
return true;
}
}好了分享结束~