Springboot响应参数加密

import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.base.annotation.AESBody;
import com.test.base.annotation.DisableSecret;
import com.test.base.config.SecretConfig;
import com.test.common.constant.CommonConstant;
import com.test.common.exception.IchibanShoException;
import com.test.common.utils.AESUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;

@Slf4j
@RestControllerAdvice
public class ResponseEncryptInterceptor implements ResponseBodyAdvice<Object> {
    @Autowired(required = false)
    private SecretConfig secretConfig;
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(@NonNull MethodParameter returnType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {
        if (Objects.isNull(secretConfig) || !secretConfig.isEnable()) {
            return false;
        }
        String genericString = returnType.getExecutable().toGenericString();
        if (StrUtil.isNotBlank(genericString) && genericString.contains("swagger")) {
            return false;
        }
        DisableSecret disableSecret = returnType.getMethodAnnotation(DisableSecret.class);
        return Objects.isNull(disableSecret);
    }

    @Override
    public Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType, @NonNull MediaType selectedContentType,
                                  @NonNull Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  @NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) {
        if (secretConfig.isEnable()) {
            log.info(">>>>>>>>>>>>>>>>>> 响应加密 开始 <<<<<<<<<<<<<<<<<<");
            String originalBody = toJsonStr(body);
            log.info("原始响应内容:{}", originalBody);
            String bodyEncoded = URLEncodeUtil.encode(originalBody);//前端RSA分段解密中文乱码处理
            AESBody aesBody = returnType.getMethodAnnotation(AESBody.class);
            if (Objects.nonNull(aesBody)) {
                String aesKey = RandomUtil.randomString(secretConfig.getAesKeyLength());
                bodyEncoded = aesKey + AESUtil.encryptStr(bodyEncoded, aesKey);//AES加密,前端使用ECB模式,pad.Pkcs7解密
                log.info("AES加密后的响应内容:{}", bodyEncoded);
            }
            String frontPrivateKey = secretConfig.getFrontPrivateKey();
            String frontPublicKey = secretConfig.getFrontPublicKey();
            if (StrUtil.isNotBlank(frontPublicKey)) {
                RSA rsa = SecureUtil.rsa(frontPrivateKey, frontPublicKey);
                rsa.setEncryptBlockSize(CommonConstant.RSA_ENCRYPT_BLOCK_SIZE);//hutool RSA分段加密块大小,默认117
                body = rsa.encryptBase64(bodyEncoded, KeyType.PublicKey);
                log.info("RSA加密后的响应内容:{}", body);
            }
            log.info(">>>>>>>>>>>>>>>>>> 响应加密 结束 <<<<<<<<<<<<<<<<<<");
        }
        return body;
    }

    private String toJsonStr(Object body) {
        try {
            return objectMapper.writeValueAsString(body);
        } catch (Exception e) {
            log.error("响应信息转JSON出错", e);
            throw new IchibanShoException("响应信息转JSON出错");
        }
    }
}

  

posted @ 2024-12-06 16:48  浪天涯&*  阅读(58)  评论(0)    收藏  举报