Browse Source

aipt加密解密测试

zhaops 5 years ago
parent
commit
1b8cf9942b

+ 443 - 0
aipt-service/src/main/java/com/diagbot/aop/CryptInterceptor.java

@@ -0,0 +1,443 @@
+package com.diagbot.aop;
+
+import com.diagbot.annotation.CryptField;
+import com.diagbot.util.CryptUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.binding.MapperMethod;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.session.defaults.DefaultSqlSession;
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @Description: 数据库加解密
+ * @author: gaodm
+ * @time: 2019/12/30 18:38
+ */
+@Intercepts({
+        @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
+        @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class })
+})
+@Component
+public class CryptInterceptor implements Interceptor {
+
+    private static final String PARAM = "param";
+
+    private static final String PARAM_TYPE_LIST = "list";
+
+    private static final String PARAM_TYPE_COLLECTION = "collection";
+
+    private static final String MAPPEDSTATEMENT_ID_SEPERATOR = ".";
+
+    /**
+     * 适用于加密判断
+     */
+    private static final ConcurrentHashMap<String, Set<String>> METHOD_PARAM_ANNOTATIONS_MAP = new ConcurrentHashMap<>();
+    /**
+     * 适用于解密判断
+     */
+    private static final ConcurrentHashMap<String, Boolean> METHOD_ANNOTATIONS_MAP = new ConcurrentHashMap<>();
+
+    public CryptInterceptor() {
+
+    }
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        Object[] args = invocation.getArgs();
+        // 入参
+        Object parameter = args[1];
+        MappedStatement statement = (MappedStatement) args[0];
+        // 判断是否需要解析
+        if (!isNotCrypt(parameter)) {
+            // 单参数 string
+            if (parameter instanceof String) {
+                args[1] = stringEncrypt((String) parameter, getParameterAnnotations(statement));
+                // 单参数 list
+            } else if (parameter instanceof DefaultSqlSession.StrictMap) {
+                DefaultSqlSession.StrictMap<Object> strictMap = (DefaultSqlSession.StrictMap<Object>) parameter;
+                for (Map.Entry<String, Object> entry : strictMap.entrySet()) {
+                    if (entry.getKey().contains(PARAM_TYPE_COLLECTION)) {
+                        continue;
+                    }
+                    if (entry.getKey().contains(PARAM_TYPE_LIST)) {
+                        Set<String> set = getParameterAnnotations(statement);
+                        listEncrypt((List) entry.getValue(), !set.isEmpty());
+                    }
+                }
+                // 多参数
+            } else if (parameter instanceof MapperMethod.ParamMap) {
+                MapperMethod.ParamMap<Object> paramMap = (MapperMethod.ParamMap<Object>) parameter;
+                Set<String> set = getParameterAnnotations(statement);
+                boolean setEmpty = set.isEmpty();
+                // 解析每一个参数
+                for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
+                    // 判断不需要解析的类型 不解析map
+                    if (isNotCrypt(entry.getValue()) || entry.getValue() instanceof Map || entry.getKey().contains(PARAM)) {
+                        continue;
+                    }
+                    // 如果string
+                    if (entry.getValue() instanceof String) {
+                        entry.setValue(stringEncrypt(entry.getKey(), (String) entry.getValue(), set));
+                        continue;
+                    }
+                    boolean isSetValue = !setEmpty && set.contains(entry.getKey());
+                    // 如果 list
+                    if (entry.getValue() instanceof List) {
+                        listEncrypt((List) entry.getValue(), isSetValue);
+                        continue;
+                    }
+                    beanEncrypt(entry.getValue());
+                }
+                // bean
+            } else {
+                beanEncrypt(parameter);
+            }
+        }
+
+        // 获得出参
+        Object returnValue = invocation.proceed();
+
+        // 出参解密
+        if (isNotCrypt(returnValue)) {
+            return returnValue;
+        }
+        Boolean bo = getMethodAnnotations(statement);
+        if (returnValue instanceof String && bo) {
+            return stringDecrypt((String) returnValue);
+        }
+        if (returnValue instanceof List) {
+            listDecrypt((List) returnValue, bo);
+            return returnValue;
+        }
+
+        return returnValue;
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        return Plugin.wrap(target, this);
+    }
+
+    @Override
+    public void setProperties(Properties properties) {
+
+    }
+
+    /**
+     * 获取 方法上的注解
+     *
+     * @param statement
+     * @return
+     * @throws ClassNotFoundException
+     */
+    private Boolean getMethodAnnotations(MappedStatement statement) throws ClassNotFoundException {
+        final String id = statement.getId();
+        Boolean bo = METHOD_ANNOTATIONS_MAP.get(id);
+        if (bo != null) {
+            return bo;
+        }
+        Method m = getMethodByMappedStatementId(id);
+        if (m == null) {
+            return Boolean.FALSE;
+        }
+        final CryptField cryptField = m.getAnnotation(CryptField.class);
+        // 如果允许解密
+        if (cryptField != null && cryptField.decrypt()) {
+            bo = Boolean.TRUE;
+        } else {
+            bo = Boolean.FALSE;
+        }
+        Boolean bo1 = METHOD_ANNOTATIONS_MAP.putIfAbsent(id, bo);
+        if (bo1 != null) {
+            bo = bo1;
+        }
+
+        return bo;
+    }
+
+    /**
+     * 获取 方法参数上的注解
+     *
+     * @param statement
+     * @return
+     * @throws ClassNotFoundException
+     */
+    private Set<String> getParameterAnnotations(MappedStatement statement) throws ClassNotFoundException {
+        final String id = statement.getId();
+        Set<String> set = METHOD_PARAM_ANNOTATIONS_MAP.get(id);
+        if (set != null) {
+            return set;
+        }
+        set = new HashSet<>();
+        Method m = getMethodByMappedStatementId(id);
+        if (m == null) {
+            return set;
+        }
+        final Annotation[][] paramAnnotations = m.getParameterAnnotations();
+        // get names from @CryptField annotations
+        for (Annotation[] paramAnnotation : paramAnnotations) {
+            for (Annotation annotation : paramAnnotation) {
+                if (annotation instanceof CryptField) {
+                    CryptField cryptField = (CryptField) annotation;
+                    // 如果允许加密
+                    if (cryptField.encrypt()) {
+                        set.add(cryptField.value());
+                    }
+                    break;
+                }
+            }
+        }
+
+        Set<String> oldSet = METHOD_PARAM_ANNOTATIONS_MAP.putIfAbsent(id, set);
+        if (oldSet != null) {
+            set = oldSet;
+        }
+
+        return set;
+    }
+
+    /**
+     * 通过mappedStatementId get Method
+     *
+     * @param id
+     * @return
+     * @throws ClassNotFoundException
+     */
+    private Method getMethodByMappedStatementId(String id) throws ClassNotFoundException {
+        Method m = null;
+        final Class clazz = Class.forName(id.substring(0, id.lastIndexOf(MAPPEDSTATEMENT_ID_SEPERATOR)));
+        for (Method method : clazz.getMethods()) {
+            if (method.getName().equals(id.substring(id.lastIndexOf(MAPPEDSTATEMENT_ID_SEPERATOR) + 1))) {
+                m = method;
+                break;
+            }
+        }
+
+        return m;
+    }
+
+    /**
+     * 判断是否需要加解密
+     *
+     * @param o
+     * @return
+     */
+    private boolean isNotCrypt(Object o) {
+        return o == null || o instanceof Double || o instanceof Integer || o instanceof Long || o instanceof Boolean;
+    }
+
+    /**
+     * String 加密
+     *
+     * @param str
+     * @return
+     * @throws Exception
+     */
+    private String stringEncrypt(String str) throws Exception {
+        return stringEncrypt(null, str, null, null);
+    }
+
+    /**
+     * String 加密
+     *
+     * @param str
+     * @param set
+     * @return
+     * @throws Exception
+     */
+    private String stringEncrypt(String str, Set<String> set) throws Exception {
+        return stringEncrypt(null, str, set, true);
+    }
+
+    /**
+     * String 加密
+     *
+     * @param name
+     * @param str
+     * @param set
+     * @return
+     * @throws Exception
+     */
+    private String stringEncrypt(String name, String str, Set<String> set) throws Exception {
+        return stringEncrypt(name, str, set, false);
+    }
+
+    /**
+     * String 加密
+     *
+     * @param name
+     * @param str
+     * @param set
+     * @param isSingle
+     * @return
+     * @throws Exception
+     */
+    private String stringEncrypt(String name, String str, Set<String> set, Boolean isSingle) throws Exception {
+        if (StringUtils.isBlank(str)) {
+            return str;
+        }
+        if (isSingle == null) {
+            //todo 加密实现
+            str = CryptUtil.encrypt_char(str);
+            return str;
+        }
+        if (isSingle && set != null && !set.isEmpty()) {
+            //todo 加密实现
+            str = CryptUtil.encrypt_char(str);
+            return str;
+        }
+        if (!isSingle && set != null && !set.isEmpty() && set.contains(name)) {
+            //todo 加密实现
+            str = CryptUtil.encrypt_char(str);
+            return str;
+        }
+
+        return str;
+    }
+
+    /**
+     * String 解密
+     *
+     * @param str
+     * @return
+     */
+    private String stringDecrypt(String str) {
+        if (StringUtils.isBlank(str)) {
+            return str;
+        }
+//        String[] array = str.split("\\|");
+//        if (array.length < 2) {
+//            return str;
+//        }
+        //todo 解密实现
+        str = CryptUtil.decrypt_char(str);
+
+        return str;
+    }
+
+    /**
+     * list 加密
+     *
+     * @param list
+     * @param bo
+     * @return
+     * @throws Exception
+     */
+    private List listEncrypt(List list, Boolean bo) throws Exception {
+        for (int i = 0; i < list.size(); i++) {
+            Object listValue = list.get(i);
+            // 判断不需要解析的类型
+            if (isNotCrypt(listValue) || listValue instanceof Map) {
+                break;
+            }
+            if (listValue instanceof String && bo) {
+                list.set(i, stringEncrypt((String) listValue));
+                continue;
+            }
+            beanEncrypt(listValue);
+        }
+
+        return list;
+    }
+
+    /**
+     * list 解密
+     *
+     * @param list
+     * @param bo
+     * @return
+     * @throws Exception
+     */
+    private List listDecrypt(List list, Boolean bo) throws Exception {
+        for (int i = 0; i < list.size(); i++) {
+            Object listValue = list.get(i);
+            // 判断不需要解析的类型 获得
+            if (isNotCrypt(listValue) || listValue instanceof Map) {
+                break;
+            }
+            if (listValue instanceof String && bo) {
+                list.set(i, stringDecrypt((String) listValue));
+                continue;
+            }
+            beanDecrypt(listValue);
+        }
+
+        return list;
+    }
+
+    /**
+     * bean 加密
+     *
+     * @param val
+     * @throws Exception
+     */
+    private void beanEncrypt(Object val) throws Exception {
+        Class objClazz = val.getClass();
+        Field[] objFields = objClazz.getDeclaredFields();
+        for (Field field : objFields) {
+            CryptField cryptField = field.getAnnotation(CryptField.class);
+            if (cryptField != null && cryptField.encrypt()) {
+                field.setAccessible(true);
+                Object fieldValue = field.get(val);
+                if (fieldValue == null) {
+                    continue;
+                }
+                if (field.getType().equals(String.class)) {
+                    field.set(val, stringEncrypt((String) fieldValue));
+                    continue;
+                }
+                if (field.getType().equals(List.class)) {
+                    field.set(val, listEncrypt((List) fieldValue, Boolean.TRUE));
+                    continue;
+                }
+            }
+        }
+    }
+
+    /**
+     * bean 解密
+     *
+     * @param val
+     * @throws Exception
+     */
+    private void beanDecrypt(Object val) throws Exception {
+        Class objClazz = val.getClass();
+        Field[] objFields = objClazz.getDeclaredFields();
+        for (Field field : objFields) {
+            CryptField cryptField = field.getAnnotation(CryptField.class);
+            if (cryptField != null && cryptField.decrypt()) {
+                field.setAccessible(true);
+                Object fieldValue = field.get(val);
+                if (fieldValue == null) {
+                    continue;
+                }
+                if (field.getType().equals(String.class)) {
+                    field.set(val, stringDecrypt((String) fieldValue));
+                    continue;
+                }
+                if (field.getType().equals(List.class)) {
+                    field.set(val, listDecrypt((List) fieldValue, Boolean.TRUE));
+                    continue;
+                }
+            }
+        }
+    }
+}

+ 3 - 0
aipt-service/src/main/java/com/diagbot/entity/ConceptDetail.java

@@ -3,6 +3,7 @@ package com.diagbot.entity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.diagbot.annotation.CryptField;
 
 import java.io.Serializable;
 import java.util.Date;
@@ -64,11 +65,13 @@ public class ConceptDetail implements Serializable {
     /**
      * 提示明细内容
      */
+    @CryptField
     private String content;
 
     /**
      * 纯文本
      */
+    @CryptField
     private String text;
 
     /**

+ 32 - 0
aipt-service/src/main/java/com/diagbot/facade/ConceptDetailTestFacade.java

@@ -0,0 +1,32 @@
+package com.diagbot.facade;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.diagbot.entity.ConceptDetail;
+import com.diagbot.service.impl.ConceptDetailServiceImpl;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author:zhaops
+ * @time: 2019/12/30 20:24
+ */
+@Component
+public class ConceptDetailTestFacade extends ConceptDetailServiceImpl {
+
+    public ConceptDetail saveRecord(ConceptDetail conceptDetail) {
+        this.baseMapper.insert(conceptDetail);
+        return conceptDetail;
+    }
+
+    public ConceptDetail getById(Long id) {
+        return this.getById(id);
+    }
+
+    public List<ConceptDetail> getByParam(ConceptDetail conceptDetail) {
+        QueryWrapper<ConceptDetail> conceptDetailQueryWrapper = new QueryWrapper<>();
+        conceptDetailQueryWrapper.like("content", conceptDetail.getContent());
+        return this.list(conceptDetailQueryWrapper);
+    }
+}

+ 53 - 0
aipt-service/src/main/java/com/diagbot/web/ConceptDetailTestController.java

@@ -0,0 +1,53 @@
+package com.diagbot.web;
+
+import com.diagbot.annotation.SysLogger;
+import com.diagbot.dto.ConceptIntroduceDTO;
+import com.diagbot.dto.RespDTO;
+import com.diagbot.entity.ConceptDetail;
+import com.diagbot.facade.ConceptDetailTestFacade;
+import com.diagbot.vo.ConceptIntroduceVO;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author:zhaops
+ * @time: 2019/12/30 20:22
+ */
+@RestController
+@RequestMapping("/conceptDetailTest")
+@Api(value = "提示信息加密测试", tags = { "知识库标准化-提示信息加密测试相关API" })
+@SuppressWarnings("unchecked")
+public class ConceptDetailTestController {
+    @Autowired
+    private ConceptDetailTestFacade conceptDetailTestFacade;
+
+    @PostMapping("/saveRecord")
+    @SysLogger("saveRecord")
+    public RespDTO<ConceptIntroduceDTO> saveRecord(@Valid @RequestBody ConceptDetail conceptDetail) {
+        ConceptDetail data = conceptDetailTestFacade.saveRecord(conceptDetail);
+        return RespDTO.onSuc(data);
+    }
+
+    @PostMapping("/getById")
+    @SysLogger("getById")
+    public RespDTO<ConceptIntroduceDTO> getById(@RequestParam Long id) {
+        ConceptDetail data = conceptDetailTestFacade.getById(id);
+        return RespDTO.onSuc(data);
+    }
+
+    @PostMapping("/getByParam")
+    @SysLogger("getByParam")
+    public RespDTO<ConceptIntroduceDTO> getByParam(@Valid @RequestBody ConceptDetail conceptDetail) {
+        List<ConceptDetail> data = conceptDetailTestFacade.getByParam(conceptDetail);
+        return RespDTO.onSuc(data);
+    }
+}