采用注解方式对接口入参返回值加密解密(前台需要配套加密解密)

本文展示了如何使用Java实现AES加密和解密,并结合注解处理接口入参解密与返回值加密。示例中,定义了`RequestDecrypt`和`ResponseEncrypt`注解来标识是否需要加密或解密,并通过`RequestBodyAdvice`和`ResponseBodyAdvice`进行相应处理。

一。加密类:
@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;
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值