库表字段加密存储,查询解密

项目上有国密需求,要求重要数据得加密存储到数据库,页面是解密展示。因为表操作都是通过dao层去处理的,所以考虑直接在dao层拦截处理有加密注解的字段从而满足加解密需求。

首先需要创建个加密注解,在需要加密的字段上加上该注解,然后在拦截器那里判断是否存在该注解,有的话即进行加密处理即可,查询时,判断值是否存在加密标识的,有就进行解密即可啦。贴代码:

public class EncryptInterceptor implements MethodInterceptor {

    private final IDataCryptor encryptUtil;

    public EncryptInterceptor(IDataCryptor encryptUtil) {
        this.encryptUtil = encryptUtil;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        //方法是否有加解密注解,如果有的话,返回值为String、List<String>等类型时需要解密返回。
        EncryptField encryptField = method.getAnnotation(EncryptField.class);
        boolean hasEncryptField = false;
        if (encryptField != null){
            hasEncryptField = true;
        }
        encrypt(invocation);
        Object returnParam = invocation.proceed();
        return decrypt(returnParam, hasEncryptField);
    }

    /**
     * 加密
     */
    public void encrypt(MethodInvocation invocation){
        Object[] params = invocation.getArguments();
        Method method = invocation.getMethod();
        Annotation[][] annotations = method.getParameterAnnotations();
        if (params.length != 0) {
            for (int i = 0; i < params.length; i++) {
                Object o = params[i];
                if (o != null) {
                    boolean hasEncryptField =false;
                    Annotation[] paramAnn = annotations[i];
                    for (Annotation annotation : paramAnn) {
                        //判断当前参数是否有注解为EncryptField
                        if (annotation.annotationType().equals(EncryptField.class)) {
                           hasEncryptField = true;
                           break;
                        }
                    }
                    if (o instanceof String) {
                        //没有加密注解,跳过
                        if (!hasEncryptField) {
                            continue;
                        }
                        params[i] = handlerString(o, true);
                    } else {
                        params[i] = handler(o, true, hasEncryptField);
                    }
                }
            }
        }
    }

    /**
     * 解密
     * @param  hasEncryptField 返回参数是String、List<String>等类型时,是否解密。
     */
    public Object decrypt(Object obj, boolean hasEncryptField){
        if (obj != null) {
            if (obj instanceof String && hasEncryptField) {
                return handlerString(obj, false);
            } else {
                return handler(obj, false, hasEncryptField);
            }
        }
        return obj;
    }

    /**
     * 处理String类型的请求、响应参数
     * @param obj
     * @param isEncrypt
     * @return
     */
    private Object handlerString (Object obj, boolean isEncrypt){
        if (Objects.isNull(obj)) {
            return obj;
        }
        String realValue = String.valueOf(obj);
        if (isEncrypt && !encryptUtil.isEncrypted(realValue)) {
            obj = encryptUtil.encrypt(realValue);
        } else if (!isEncrypt && encryptUtil.isEncrypted(realValue)) {
            obj = encryptUtil.decrypt(realValue);
        }
        return obj;
    }

    /**
     * 加密Object 类型的参数
     * @param obj
     * @param isEncrypt
     * @param hasEncryptField  请求、返回参数是List<String>等类型时否需要加解密。
     * @return
     */
    private Object handler(Object obj, boolean isEncrypt, boolean hasEncryptField){
        if (Objects.isNull(obj)) {
            return null;
        }
        if (obj instanceof Collection) {
            Collection<Object> old = CheckUtil.cast(obj);
            Collection<Object> result;
            if (old instanceof List) {
                result = new ArrayList<>();
            } else {
                result = new LinkedHashSet<>();
            }
            for (Object o : old) {
                result.add(handler(o, isEncrypt, hasEncryptField));
            }
            return result;
        }else if (obj instanceof Map) {
            Map<Object,Object> old = CheckUtil.cast(obj);
            Map<Object,Object> result = new LinkedHashMap<>();
            for(Map.Entry<Object,Object> ent : old.entrySet()) {
                result.put(ent.getKey(), handler(ent.getValue(), isEncrypt, hasEncryptField));
            }
            return result;
        }else if (obj.getClass().isArray()) {
            int len = Array.getLength(obj);
            for(int ix = 0; ix < len; ++ix)
            {
                Object elem = Array.get(obj, ix);
                Array.set(obj, ix, handler(elem, isEncrypt, hasEncryptField));
            }
            return obj;
        }else if (obj instanceof Optional){
            Optional<Object> old=CheckUtil.cast(obj);
            Optional<Object> result = old;
            if (old.isPresent()){
                Object rvalue = handler(old.get(), isEncrypt, hasEncryptField);
                result = Optional.of(rvalue);
            }
            return result;
        } else if (obj instanceof Slice){
            Slice<Object> old = CheckUtil.cast(obj);
            Slice<Object> result = old;
            if(old.hasContent()) {
                //如果是Slice类型,且有内容,则一定是List类型值
                Object content = old.getContent();
                content = handler(content, isEncrypt, hasEncryptField);
                List<Object> data=CheckUtil.cast(content);
                result = new PageImpl<>(data, old.getPageable(), data.size());
            }
            return result;
        } else if (obj instanceof String && hasEncryptField){
            return handlerString(obj, isEncrypt);
        } else if (!isBaseType(obj)){
            Object result = obj;
            if (!isEncrypt && result instanceof EncryptCloneable){
                result = ((EncryptCloneable) result).clone();
            }
            handlerObject(result,isEncrypt);
            return result;
        }
        return obj;
    }

    private void handlerObject(Object obj, boolean isEncrypt){
        if (Objects.isNull(obj)) {
            return ;
        }
        List<Field> fields = getAllField(obj);
        for (Field field : fields) {
            boolean hasEncryptField = field.isAnnotationPresent(EncryptField.class);
            if (hasEncryptField) {
                try{
                    field.setAccessible(true);
                    String realValue = (String) field.get(obj);
                    if (StringUtils.isNotBlank(realValue)) {
                        String value = realValue;
                        if (isEncrypt && hasEncryptField && !encryptUtil.isEncrypted(realValue)) {
                            value = encryptUtil.encrypt(realValue);
                        } else if (!isEncrypt && hasEncryptField && encryptUtil.isEncrypted(realValue)) {
                            value = encryptUtil.decrypt(realValue);
                        }
                        field.set(obj, value);
                    }
                }catch(Exception e){
                    // 如果处理出错,则不改变值
                    log.warn("对字段" + field.getName() + "处理加解密时出错:", e);
                }
            }
        }
    }

    private static List<Field> getAllField(Object model) {
        Class<?> clazz = model.getClass();
        List<Field> fields = new ArrayList<>();
        //只要父类存在,就获取其类的属性到集合
        while (clazz != null) {
            fields.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            //获取其父类
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    /**
     * 检查是否基础类型,这些不做加解密处理
     *
     * @param obj
     * @return
     */
    private boolean isBaseType(Object obj)
    {
        if(obj.getClass().isPrimitive()) {
            return true;
        }
        return obj instanceof Boolean
                || obj instanceof Byte
                || obj instanceof Character
                || obj instanceof Short
                || obj instanceof Integer
                || obj instanceof Long
                || obj instanceof Float
                || obj instanceof Double
                || obj instanceof Date;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值