设计通用请求与返回加解密处理

不问归期 提交于 2020-08-08 04:37:58

1. 场景

1.要求对接口中部分输入和输出参数进行加解密。如密码要求前端加密后传给后端进行解密。

2.对整个请求头requestBody和返回内容ResponseBody进行加解密,如涉及到金额时,整个请求内容都加密传输。

2.解决方案

为了减少代码的侵入,采用注解形式进行处理。

/**
 * 进行参数解密
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DecryptField {
    String algorithm() default "AES";
}


/**
 * 进行参数加密
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptField {
    String algorithm() default "AES";
}

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DecryptRequestBody {
    boolean decryptBody()  default false;
    boolean decryptField() default false;
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptResponseBody {
    boolean encryptBody()  default false;
    boolean encryptField() default false;
}
public class CryptoAnnotationHandler {
    private final static Logger logger = LogManager.getLogger(CryptoAnnotationHandler.class);


    public static boolean handle(Object obj) {
	return handle(obj,EncryptUtils.KEY);

    }
    @SuppressWarnings("unchecked")
    public static boolean handle(Object obj,String key) {
	if (obj instanceof Collection) {
	    Collection<Object> objects = (Collection<Object>) obj;
	    for (Object object : objects) {
		try {
		    endecryptObject(object,key);

		} catch (Exception e1) {
		   logger.error("加解密出错",e1);
		   return false;
		}
	    }
	} else {
	    try {
		endecryptObject(obj,key);
	    } catch (Exception e1) {
		 logger.error("加解密出错",e1);
		 return false;
	    }
	}
	return true;
    }
    /**
     * 只支持最一层会字符串的才可以加解密操作
     * 
     * @param requestObj
     * @throws IllegalAccessException
     */
    private static void endecryptObject(Object requestObj,String key) throws Exception {
	if (Objects.isNull(requestObj)) {
	    return;
	}
	Field[] fields = requestObj.getClass().getDeclaredFields();
	for (Field field : fields) {
	    if (field.getType().equals(String.class)) {
		// 若该字段被EncryptField注解,则进行解密
		DecryptField deAnnotation = AnnotationUtils.findAnnotation(field, DecryptField.class);
		if (null != deAnnotation) {
		    // 设置private类型允许访问
		    field.setAccessible(Boolean.TRUE);
		    if(AlgorithmEnum.DES.getCode().equals(deAnnotation.algorithm())){
			 field.set(requestObj, EncryptUtils.decryptByDes((String) field.get(requestObj),key));
		    }else if(AlgorithmEnum.AES.getCode().equals(deAnnotation.algorithm())){
			field.set(requestObj, EncryptUtils.decryptByAes((String) field.get(requestObj),key));
		    }else{
			throw new CryptoException("不支持算法:"+deAnnotation.algorithm());
		    }
		    field.setAccessible(Boolean.FALSE);
		}

		EncryptField enAnnotation = AnnotationUtils.findAnnotation(field, EncryptField.class);
		if (null != enAnnotation) {
		    // 设置private类型允许访问
		    field.setAccessible(Boolean.TRUE);
		    if(AlgorithmEnum.DES.getCode().equals(enAnnotation.algorithm())){
			 field.set(requestObj, EncryptUtils.encryptByDes((String) field.get(requestObj),key));
		    }else if(AlgorithmEnum.AES.getCode().equals(enAnnotation.algorithm())){
			field.set(requestObj, EncryptUtils.encryptByAes((String) field.get(requestObj),key));
		    }else{
			throw new CryptoException("不支持算法:"+enAnnotation.algorithm());
		    }
		   
		    field.setAccessible(Boolean.FALSE);
		}
	    } 

	}

    }

}
@RestControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
	return returnType.hasMethodAnnotation(EncryptResponseBody.class)
		&& returnType.hasMethodAnnotation(ResponseBody.class);
    }

    @Override
    public Object beforeBodyWrite(Object obj, MethodParameter returnType, MediaType selectedContentType,
	    Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
	EncryptResponseBody a = returnType.getMethodAnnotation(EncryptResponseBody.class);

	if (null != obj) {
	    try {
		if(a.encryptField()){
		    CryptoAnnotationHandler.handle(obj,Constant.AES_KEY);
		}
		String content = (objectMapper.writeValueAsString(obj));
		if(a.encryptBody()){
		    content = EncryptUtils.encryptByAes(content,Constant.AES_KEY);
		}
		if(logger.isDebugEnabled()){
		    logger.debug("返回加密数据:{}",content);
		}
	    } catch (IOException e) {
		throw new CryptoException("加密失败");
	    }
	}

	return obj;
    }
}



@RestControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
	return methodParameter.hasParameterAnnotation(DecryptRequestBody.class)
		&& methodParameter.hasParameterAnnotation(RequestBody.class);
    }

    @Override
    public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter,
	    Type type, Class<? extends HttpMessageConverter<?>> aClass) {
	return o;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter,
	    Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
	DecryptRequestBody a = methodParameter.getParameterAnnotation(DecryptRequestBody.class);

	return new HttpInputMessage() {
	    @Override
	    public InputStream getBody() throws IOException {
		String srcReqestBody = IOUtils.toString(httpInputMessage.getBody(), "UTF-8");
		if(logger.isDebugEnabled()){
		    logger.debug("原始加密请求数据:{}",srcReqestBody);
		}
		if (a.decryptBody()) {
		    try {
			String decrpyt = EncryptUtils.decryptByAes(
				srcReqestBody, Constant.AES_KEY);
			return new ByteArrayInputStream(decrpyt.getBytes(StandardCharsets.UTF_8));
		    } catch (Exception e) {
			throw new CryptoException("解密失败");
		    }
		} else {
		    return new ByteArrayInputStream(srcReqestBody.getBytes(
			    StandardCharsets.UTF_8));
		}

	    }

	    @Override
	    public HttpHeaders getHeaders() {
		return httpInputMessage.getHeaders();
	    }
	};
    }

    @Override
    public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter,
	    Type type, Class<? extends HttpMessageConverter<?>> aClass) {
	DecryptRequestBody a = methodParameter.getParameterAnnotation(DecryptRequestBody.class);
	if (a.decryptField()) {
	    boolean r = CryptoAnnotationHandler.handle(o, Constant.AES_KEY);
	    if (!r) {
		throw new CryptoException("解密失败");
	    }
	}
	return o;
    }
}

 

参考: https://gitee.com/pengchua/restapi/tree/master/openapi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!