mybaits plus 字段加密与解密

mybaits plus 字段加密与解密

  1. 写在前面
    在我们实际开发中有的时候需要保证数据的安全,那么这个时候我们就需要对我们存储的数据加密,数据加密可以用很多方法实现,比如数据库加密,java代码加密和orm框架加密等等。

思考这么多加密方式我们应该选择那种方式?
1.数据库加密:主流数据库都提供了一系列的加密功能,如:AES_DECRYPT,DECODE等等
2.java代码: 通过java代码实现对字段的加密和解密

在这里我选择扩展mybaits plus框架实现加密
1.实现加密算法,这里我们选址aes对称加密算法,因为它是可逆算法。详情可参考AES加密算法的详细介绍与实现。 具体代码实现如下

package com.flow.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
 *  aes 加密的工具类
 *  1.存储 加密的秘钥key
 *  2.实现 aes 加密
 *  3.实现aes解密的功能
 */
public class AES {

    // 定义 aes 加密的key
    // 密钥  必须是16位, 自定义,
    // 如果不是16位, 则会出现InvalidKeyException: Illegal key size
    //  解决方案有两种:
    //1.需要安装Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files(可以在Oracle下载).
    //2.设置设置key的长度为16个字母和数字的字符窜(128 Bit/8=16字符)就不报错了。
    private static String key = "KEYJSDKKYHKLSSWS";

    //定义加密的编码
    private static String charset = "utf-8";

    // 偏移量
    private static int offset = 16;
    private static String transformation = "AES/CBC/PKCS5Padding";
    private static String algorithm = "AES";

    /**
     * 加密
     *
     * @param content
     * @return
     */
    public static String encrypt(String content) {
        return encrypt(content, key);
    }

    /**
     * 解密
     *
     * @param content
     * @return
     */
    public static String decrypt(String content) {
        return decrypt(content, key);
    }

    /**
     * 加密
     *
     * @param content 需要加密的内容
     * @param key     加密密码
     * @return
     */
    public static String encrypt(String content, String key) {
        try {
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
            IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
            Cipher cipher = Cipher.getInstance(transformation);
            byte[] byteContent = content.getBytes(charset);
            cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return new Base64().encodeToString(result); // 加密
        } catch (Exception e) {
            // LogUtil.exception(e);
        }
        return null;
    }

    /**
     * AES(256)解密
     *
     * @param content 待解密内容
     * @param key     解密密钥
     * @return 解密之后
     * @throws Exception
     */
    public static String decrypt(String content, String key) {
        try {

            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
            IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
            Cipher cipher = Cipher.getInstance(transformation);
            cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化
            byte[] result = cipher.doFinal(new Base64().decode(content));
            return new String(result); // 解密
        } catch (Exception e) {
            //LogUtil.exception(e);
        }
        return null;
    }

}

  1. 扩展mybatis BaseTypeHandler 类 详解请看:mybatis中typehandler详解,具体实现代码如下:
package com.flow.types;

import com.flow.utils.AES;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AesTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, AES.encrypt(parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return AES.decrypt(rs.getString(columnName));
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return AES.decrypt(rs.getString(columnIndex));
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return AES.decrypt(cs.getString(columnIndex));
    }
}

  1. 最后通过mybaits plus @TableField使用该转换器代码如下:
@TableName(autoResultMap = true)
// @TableName 注解的 autoResultMap 一定要为true 否则查询得到的结果会为null
public class Estate extends BaseEntity<Long> {
    private static final long serialVersionUID = 4470647135587698365L;
    /**
     * 物业公司的编号
     */
    @TableElement(title = "物业编号")
    @FormField(title = "物业编号", isSearch = true, isSubmit = false)
    private String number;

    /**
     * 物业公司的名称
     */
    @FormField(title = "物业公司名称", order = 1, isSearch = true, isSubmit = false)
    @TableElement(title = "物业公司名称", order = 1)
    @TableField(typeHandler = AesTypeHandler.class)
    private String realEstateName;

    /**
     * 业主的姓名
     */
    @FormField(title = "业主姓名", order = 2, isSearch = true, isSubmit = false)
    @TableElement(title = "业主姓名", order = 2)
    private String realName;

    /**
     * 业主身份证点好
     */
    @TableElement(title = "业主身份证号码", order = 3)
    @TableField(typeHandler = AesTypeHandler.class)
    private String identity;

    /**
     * 业主的电话
     */
    @TableElement(title = "业主电话号码", order = 4)
    private String mobile;

    /**
     * 物业坐落
     */
    @TableField(typeHandler = AesTypeHandler.class)
    private String address;

    /**
     * 建筑面积
     */
    private BigDecimal architecture;

    /**
     * 使用面积
     */
    @TableField(value = "`use`")
    private BigDecimal use;

    /**
     * 物业性质
     */
    @EnumValue
    private String nature;

}
  1. 测试结果
    插入结果如下:
    在这里插入图片描述
    请求接口如下
    在这里插入图片描述
    友情提示:由于数据库存储的是加密后的结果,所以不能把加密字段当做模糊查询的条件字段,故谨慎使用。

你可能感兴趣的:(mybaits,java,安全,开发语言)