一。加密类:
@Slf4j
@Component
public class AES {
//加密用的Key 可以用26个字母和数字组成 此处使用AES-128-CBC加密模式,key需要为16位。
private static final String sKey = “1234567890asdfgh”;
private static final String ivParameter = “1234567891234567”;//向量
private static final SecretKeySpec skeySpec;
private static final IvParameterSpec iv;
static{
skeySpec = new SecretKeySpec(sKey.getBytes(StandardCharsets.UTF_8), "AES");
iv = new IvParameterSpec(ivParameter.getBytes());
}
private AES() { }
// 加密
public static String encrypt(String encData) throws Exception {
if(StringUtils.isBlank(encData)) return encData;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
return Base64.getEncoder().encodeToString(cipher.doFinal(encData.getBytes(StandardCharsets.UTF_8)));
}
// 解密
public static String decrypt(String sSrc) throws Exception{
if(StringUtils.isBlank(sSrc)) return sSrc;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
return new String(cipher.doFinal(Base64.getDecoder().decode(sSrc)), StandardCharsets.UTF_8);
}
public static void main(String[] arg) throws Exception {
String sendString = "Hello123@#¥%……!";
String result = AES.encrypt(sendString);
log.info(result);
result = AES.decrypt(result);
log.info(result);
}
}
二。入参解密
1.注解
@Target({ElementType.METHOD , ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestDecrypt {
boolean value() default true;
}
2.解析处理注解
public class NeedCrypto {
public static boolean needEncrypt(MethodParameter returnType) {
boolean encrypt = false;
boolean classPresentAnno = returnType.getContainingClass().isAnnotationPresent(ResponseEncrypt.class);
boolean methodPresentAnno = Objects.requireNonNull(returnType.getMethod()).isAnnotationPresent(ResponseEncrypt.class);
if (classPresentAnno) {
encrypt = returnType.getContainingClass().getAnnotation(ResponseEncrypt.class).value();
if (!encrypt) return false;
}
if (methodPresentAnno) encrypt = returnType.getMethod().getAnnotation(ResponseEncrypt.class).value();
return encrypt;
}
public static boolean needDecrypt(MethodParameter parameter) {
boolean decrypt = false;
boolean classPresentAnno = parameter.getContainingClass().isAnnotationPresent(RequestDecrypt.class);
boolean methodPresentAnno = Objects.requireNonNull(parameter.getMethod()).isAnnotationPresent(RequestDecrypt.class);
if (classPresentAnno) {
decrypt = parameter.getContainingClass().getAnnotation(RequestDecrypt.class).value();
if (!decrypt) return false;
}
if (methodPresentAnno) decrypt = parameter.getMethod().getAnnotation(RequestDecrypt.class).value();
return decrypt;
}
}
3.接口入参过滤处理
@Slf4j
@RestControllerAdvice
public class RequestDecryptAdvice implements RequestBodyAdvice {
@Override
public boolean supports(@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return false;
//log.info(“supports >> methodParameter={},type={},aClass={}”, methodParameter, type, aClass.getSimpleName());
return true;
}
@Override
public @NonNull
HttpInputMessage beforeBodyRead(@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
if (NeedCrypto.needDecrypt(methodParameter)) {
//log.info("type={},aClass={}",type,aClass);
//log.info("**************************我是RequestDecryptAdvice解密操作**************************");
return new HttpInputMessage() {
@Override
public @NonNull
InputStream getBody() throws IOException {
String bodyStr = IOUtils.toString(httpInputMessage.getBody(), StandardCharsets.UTF_8);
String newBodyStr=null;
try {
newBodyStr = AES.decrypt(bodyStr);
log.debug("请求密文={}",bodyStr);
log.info("请求明文={}",newBodyStr);
} catch (Exception exception) {
log.error("bodyStr={},newBodyStr={}",bodyStr,newBodyStr);
log.error(exception.getLocalizedMessage(),exception);
throw new IOException(exception.getMessage(),exception);
}
//log.info("bodyStr={},newBodyStr={}",bodyStr,newBodyStr);
return IOUtils.toInputStream(newBodyStr,StandardCharsets.UTF_8);
}
@Override
public @NonNull
HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
};
}
return httpInputMessage;
}
@Override
public @NonNull
Object afterBodyRead(@NonNull Object o,
@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
//log.info("afterBodyRead >> object={},httpInputMessage={},methodParameter={},type={},aClass={}", o, httpInputMessage, methodParameter, type, aClass.getSimpleName());
return o;
}
@Override
public Object handleEmptyBody(Object o,
@NonNull HttpInputMessage httpInputMessage,
@NonNull MethodParameter methodParameter,
@NonNull Type type,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return null;
//log.info("handleEmptyBody >> object={},httpInputMessage={},methodParameter={},type={},aClass={}", o, httpInputMessage, methodParameter, type, aClass.getSimpleName());
return o;
}
}
三。返回值加密
1.注解
@Target({ElementType.METHOD , ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseEncrypt {
boolean value() default true;
}
2.处理同解密
3.接口返回处理
@Slf4j
@RestControllerAdvice
public class ResponseEncryptAdvice implements ResponseBodyAdvice {
@Resource
private ObjectMapper jacksonObjectMapper;
@Override
public boolean supports(@NonNull MethodParameter methodParameter,
@NonNull Class<? extends HttpMessageConverter<?>> aClass) {
//return false;
//log.info("supports >> methodParameter={},aClass={}", methodParameter, aClass.getSimpleName());
return true;
}
@Override
@SuppressWarnings({"unchecked","rawtypes"})
public Object beforeBodyWrite(Object o,
@NonNull MethodParameter methodParameter,
@NonNull MediaType mediaType,
@NonNull Class<? extends HttpMessageConverter<?>> aClass,
@NonNull ServerHttpRequest serverHttpRequest,
@NonNull ServerHttpResponse serverHttpResponse) {
if (NeedCrypto.needEncrypt(methodParameter)) {
//log.info("beforeBodyWrite >> o={},methodParameter={},mediaType={},aClass={}", o, methodParameter, mediaType, aClass.getSimpleName());
if (o instanceof ReturnObject) {
final ReturnObject<Object> returnObject = (ReturnObject) o;
final Object t = returnObject.getT();
if (Objects.nonNull(t)) {
try {
String str = jacksonObjectMapper.writeValueAsString(t);
//log.info("**************************我是ResponseEncryptAdvice加密操作**************************");
log.debug("响应明文:{}",str);
returnObject.setT(AES.encrypt(str));
return returnObject;
} catch (Exception e) {
log.error(e.getMessage(), e);
return new ReturnObject<>(ConstantOfReturnCode.GLOBAL_RESULT_FALSE, e.getLocalizedMessage());
}
}
}
}
return o;
}
}
本文展示了如何使用Java实现AES加密和解密,并结合注解处理接口入参解密与返回值加密。示例中,定义了`RequestDecrypt`和`ResponseEncrypt`注解来标识是否需要加密或解密,并通过`RequestBodyAdvice`和`ResponseBodyAdvice`进行相应处理。
&spm=1001.2101.3001.5002&articleId=119737021&d=1&t=3&u=cbf615b5fea94336906092e39f2c3c7b)
6012

被折叠的 条评论
为什么被折叠?



