项目上有国密需求,要求重要数据得加密存储到数据库,页面是解密展示。因为表操作都是通过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; } } |