如题,我们客户有要求 敏感字段 入库要加密处理。以及有权限的人登录后还可查看原文。看到反馈区有社友使用数据库的函数加密,感觉不妥。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; } }
好了分享结束~