对返回ID加密处理返回方案

一,先创建注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface IdEncrypt {

    /**
     * 是否需要对请求参数进行解密
     *
     * @return
     */
    boolean reqHandle();

    /**
     * 加密的参数位置
     *
     * @return
     */
    int reqEncryptIndex() default 0;

    String encryptPath() default "";

    /**
     * 解密的参数位置
     *
     * @return
     */
    int reqDecryptIndex() default 0;;

    boolean isObject() default false;


    /**
     * 返回结果处理 -(原id置空或置0处理)
     *
     * @return
     */
    String sourcePath();

    /**
     * 返回结果处理 - 加密后id的路径
     *
     * @return
     */
    String rewritePath();

    /**
     * 返回结果处理 - 加密后id的名称
     *
     * @return
     */
    //String rewriteParam();

    //业务类型:news,course,sms...
    BusinsTypeEnum type() ;

    /**
     * 看返回的data组装数据是list还是map格式的及是否需要加密unencrypt
     * @return
     */
    ReturnDataTypeEnum dataType();
}

二,创建切面拦截注解,处理自己的业务

@Aspect
@Component
@Slf4j
public class IdEncryptHandlerAspect {


    public static final String PASSWORD = "course:xcc:2022";

    //文章ID,大于这个ID的文章获取详情时都要进行解密操作
    public static final Long newsId = 6937225l;

    @Resource
    private EncryptBodyConfig config;

    @Pointcut("@annotation(com.dtguai.encrypt.annotation.encrypt.IdEncrypt)")
    public void pointCut() {

    }

    /**
     *  处理请求参数,转换为解密后的数据并覆盖请求参数
     * @param obj 请求参数
     * @param idEncryptHandler  注解类
     * @return
     */
    private Object[] dealRequestParamData(Object[] obj, IdEncrypt idEncryptHandler){
        //业务类型
        BusinsTypeEnum businsTypeEnum = idEncryptHandler.type();
        if(obj[idEncryptHandler.reqEncryptIndex()] instanceof Long ){//加密参数是Long类型
            Long encryptedId = (Long) obj[idEncryptHandler.reqEncryptIndex()];
                //如果是文章业务,直接用解密后的文章ID覆盖
                if(BusinsTypeEnum.NEWS.getType().equals(businsTypeEnum.getType())){
                    log.info("文章详情接口输入的加密id值为:"+encryptedId);
                    //String decryptedId = EncryptBodyMethod.DES.getISecurity().decrypt(String.valueOf(encryptedId), PASSWORD, config);
                    //不是百度seo收录的旧文章,都要解密UUID
                    if(encryptedId!= 0 && encryptedId < newsId){
                        obj[idEncryptHandler.reqDecryptIndex()] = encryptedId;
                    }else{
                        Long decryptedId = DeAndEnUtil.decrypt(Long.valueOf(String.valueOf(encryptedId)));
                        obj[idEncryptHandler.reqDecryptIndex()] = Long.valueOf(decryptedId);
                    }
                }else{
                    //String decryptedId = EncryptBodyMethod.DES.getISecurity().decrypt(String.valueOf(encryptedId), PASSWORD, config);
                    Long decryptedId = DeAndEnUtil.decrypt(Long.valueOf(String.valueOf(encryptedId)));
                    //if(obj[idEncryptHandler.reqDecryptIndex()] instanceof Integer){ //如果入参是 Integer 类型
                     //   obj[idEncryptHandler.reqDecryptIndex()] = decryptedId.intValue();
                  //  }else if(obj[idEncryptHandler.reqDecryptIndex()] instanceof Long){ //如果入参是 Long 类型
                        obj[idEncryptHandler.reqDecryptIndex()] =decryptedId;
                    //}
                }
        }else if(obj[idEncryptHandler.reqEncryptIndex()] instanceof Integer){//加密参数是Integer类型
            Integer encryptedId = (Integer) obj[idEncryptHandler.reqEncryptIndex()];
            //如果是文章业务,直接用解密后的文章ID覆盖
            if(BusinsTypeEnum.NEWS.getType().equals(businsTypeEnum.getType())){
                log.info("文章详情接口输入的加密id值为:"+encryptedId);
                //不是百度seo收录的旧文章,都要解密UUID
                if(encryptedId!= 0 && encryptedId < newsId.intValue()){
                    obj[idEncryptHandler.reqDecryptIndex()] = encryptedId;
                }else{
                    Long decryptedId = DeAndEnUtil.decrypt(encryptedId.longValue());
                    obj[idEncryptHandler.reqDecryptIndex()] = decryptedId.intValue();
                }
            }else{
                Long decryptedId = DeAndEnUtil.decrypt(encryptedId.longValue());
                obj[idEncryptHandler.reqDecryptIndex()] =decryptedId.intValue();
            }
        }else if(obj[idEncryptHandler.reqEncryptIndex()] instanceof List){//加密参数是List类型
            List<Long> ids = new ArrayList<Long>();
            //uuid参数集合
            List<Long> encryptedIds = (List) obj[idEncryptHandler.reqEncryptIndex()];
            //原ID参数集合
            List<Long>  orginIds =  (List)  (obj[idEncryptHandler.reqDecryptIndex()]) ;
            if (CollectionUtil.isNotEmpty(encryptedIds)) {
                for(int i= 0; i< orginIds.size(); i++){
                    //如果是文章业务,则判断是否是百度seo收录的旧文章访问,小于特定的旧文章,默认都是被百度seo收录
                    if(BusinsTypeEnum.NEWS.getType().equals(businsTypeEnum.getType())){
                        //不是百度seo收录的旧文章,都要解密UUID
                        if(orginIds.get(i) != 0 && orginIds.get(i) < newsId){
                            ids.add(orginIds.get(i));
                        }else{
                            log.info("文章详情接口输入的文章uuid值为:"+orginIds.get(i));
                            //String decryptedId = EncryptBodyMethod.DES.getISecurity().decrypt(String.valueOf(encryptedIds.get(i)), PASSWORD, config);
                            Long decryptedId = DeAndEnUtil.decrypt(orginIds.get(i));
                            ids.add(decryptedId);
                        }
                    }else{
                       // String decryptedId = EncryptBodyMethod.DES.getISecurity().decrypt(String.valueOf(encryptedIds.get(i)), PASSWORD, config);\
                        Long decryptedId = DeAndEnUtil.decrypt(orginIds.get(i));
                        ids.add(decryptedId);
                    }
                }
                //if(obj[idEncryptHandler.reqDecryptIndex()] instanceof Integer){
                  //  obj[idEncryptHandler.reqDecryptIndex()] = ids.stream().mapToInt(Long::intValue).boxed().collect(Collectors.toList());
               // }else if(obj[idEncryptHandler.reqDecryptIndex()] instanceof Long){
                    obj[idEncryptHandler.reqDecryptIndex()] = ids;
               // }
            }
        }
         return obj;
    }

    @Around("pointCut()")
    public Object pointCut(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 获取注解Action
        IdEncrypt idEncryptHandler = method.getAnnotation(IdEncrypt.class);
        Object[] obj = joinPoint.getArgs();
        if (idEncryptHandler.isObject()) {
            return joinPoint.proceed(obj);
        } else {
            if (idEncryptHandler.reqHandle() || (obj.length > 0 && Objects.isNull(obj[idEncryptHandler.reqDecryptIndex()]))) {
                //对请求参数解密处理
                obj =  dealRequestParamData(obj,idEncryptHandler);
            }
            Object returnObject = joinPoint.proceed(obj);
            String jsonString = new ObjectMapper().writeValueAsString(returnObject);
            //String jsonString = JSONObject.toJSONString(returnObject,SerializerFeature.WriteDateUseDateFormat);
            ReturnDataTypeEnum returnDataTypeEnum = idEncryptHandler.dataType();

            //判断返回数据类型
            if(ReturnDataTypeEnum.MAP.getType().equals(returnDataTypeEnum.getType())){
                if(!jsonString.contains("data")){
                    return returnObject;
                }
                Map contentJson = JsonPath.parse(jsonString).read("data");
                //如果返回数据为空,不做处理
                if(CollectionUtil.isEmpty(contentJson)){
                    return returnObject;
                }
            }else if(ReturnDataTypeEnum.LIST.getType().equals(returnDataTypeEnum.getType())){
                List contentJson = JsonPath.parse(jsonString).read("data");
                //如果返回数据为空,不做处理
                if(CollectionUtil.isEmpty(contentJson)){
                    return returnObject;
                }
            }else if(ReturnDataTypeEnum.UNENCRYPT.getType().equals(returnDataTypeEnum.getType())){
                //返回数据无需处理
                return returnObject;
            }else if(ReturnDataTypeEnum.DIRECT_LIST.getType().equals(returnDataTypeEnum.getType())){
                if("[]".equals(jsonString)){//数据为空,直接返回
                    return returnObject;
                }
            }

            //对返回数据的文章uuid加密处理
            if (idEncryptHandler.rewritePath().contains("*")) {
                List<Integer> srcIds = JsonPath.parse(jsonString).read(idEncryptHandler.sourcePath());
                LinkedList newIds = new LinkedList();
                for (Integer id : srcIds) {
                    //String nid = EncryptBodyMethod.DES.getISecurity().encrypt(String.valueOf(id), PASSWORD, config);
                    Long nid = DeAndEnUtil.encrypt(Long.valueOf(String.valueOf(id)));
                    newIds.add(nid);
                }
                String returnJsonString = jsonString;
                for (int i = 0; i < newIds.size(); i++) {
                    String accuteRewritePath = idEncryptHandler.rewritePath().replace("*", String.valueOf(i));
                    String rewritePath = accuteRewritePath + ".id";
                   // returnJsonString = JsonPath.parse(returnJsonString).set(rewritePath, 0).put(accuteRewritePath, idEncryptHandler.rewriteParam(), newIds.get(i)).jsonString();
                    returnJsonString = JsonPath.parse(returnJsonString).set(rewritePath, newIds.get(i)).jsonString();

                }
                returnObject = JSONObject.parseObject(returnJsonString, returnObject.getClass());
            } else {
                Integer id = (Integer) JsonPath.parse(jsonString).read(idEncryptHandler.sourcePath());
                //String returnJsonString = JsonPath.parse(jsonString).set(idEncryptHandler.rewritePath() + ".id", 0).put(idEncryptHandler.rewritePath(), idEncryptHandler.rewriteParam(), EncryptBodyMethod.DES.getISecurity().encrypt(String.valueOf(id), PASSWORD, config)).jsonString();
                String returnJsonString = JsonPath.parse(jsonString).set(idEncryptHandler.rewritePath() + ".id", DeAndEnUtil.encrypt(Long.valueOf(String.valueOf(id)))).jsonString();

                returnObject = JSONObject.parseObject(returnJsonString, returnObject.getClass());
            }
            return returnObject;
        }
    }


    private Map<String, Object> getFieldsNameValueMap(JoinPoint joinPoint) throws Exception {
        Object[] args = joinPoint.getArgs();
        String classType = joinPoint.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        String methodName = joinPoint.getSignature().getName(); //获取方法名称
        Map<String, Object> map = new HashMap<String, Object>();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(this.getClass());
        pool.insertClassPath(classPath);
        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            throw new RuntimeException();
        }
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < cm.getParameterTypes().length; i++) {
            map.put(attr.variableName(i + pos), args[i]);//paramNames即参数名
        }
        return map;
    }
}
 

三 使用方法。

  @GetMapping("/xxxxxx")
    @IdEncrypt(reqHandle = false, sourcePath = "$.data[*].id", rewritePath = "$.data[*]",type = BusinsTypeEnum.NEWS,dataType = ReturnDataTypeEnum.LIST)
    public AjaxResult xxxxxx( @RequestParam(value="ids") int[] ids)
    {
        if(ids != null && ids.length > 0 ){
            return AjaxResult.success(appDetailService.selectAppInfoByIds(ids));
        }else{
            return AjaxResult.success();
        }
    }

四,其他枚举类

public enum BusinsTypeEnum {
    NEWS_AAAA("newsaaa", "xxxx"),
    REPORT_AAAA("reportaaa", "xxxxx");

    @EnumValue
    @JsonValue
    private final String type;
    private final String message;

    public String getType() {
        return this.type;
    }

    public String getMessage() {
        return this.message;
    }

    private BusinsTypeEnum(String type, String message) {
        this.type = type;
        this.message = message;
    }
}

五,返回的数据类型

public enum ReturnDataTypeEnum {
    LIST("list", "返回的data组装数据类型是list"),
    MAP("map", "返回的data组装数据类型是map"),
    DIRECT_LIST("directList", "非data组装直接LIST返回数据类型"),
    UNENCRYPT("unencrypt", "返回的数据不需要加密");

    @EnumValue
    @JsonValue
    private final String type;
    private final String message;

    public String getType() {
        return this.type;
    }

    public String getMessage() {
        return this.message;
    }

    private ReturnDataTypeEnum(String type, String message) {
        this.type = type;
        this.message = message;
    }
}

<think>我们使用Spring Boot的`@ControllerAdvice`和`ResponseBodyAdvice`接口来实现统一返回加密。 需求:对Controller返回的响应体进行加密加密算法使用AES,并且支持注解排除某些接口不加密。 步骤: 1. 定义加密注解,用于标记需要加密的方法或类(也可以用于标记不需要加密,根据需求) 2. 实现`ResponseBodyAdvice`接口,在写入响应体之前对数据进行加密 3. 配置AES加密工具 4. 在Controller方法上使用注解控制是否加密 注意:如果某些接口不需要加密,我们可以通过注解排除,或者通过其他条件(如URL模式)排除。 下面给出完整代码实现: </think>### 🔒 Spring Boot AOP ControllerAdvice 统一返回加密方案 下面是一个完整的统一返回加密实现方案,使用 `@ControllerAdvice` 结合自定义注解实现响应数据的自动加密处理,支持多种加密算法和灵活的策略配置。 #### 解决方案架构 ```mermaid classDiagram class EncryptedResponse { <<Record>> +String ciphertext +String algorithm } class EncryptionAdvice { +supports(MethodParameter, Class) boolean +beforeBodyWrite(Object, MethodParameter, MediaType, Class, ServerHttpRequest, ServerHttpResponse) EncryptedResponse } class EncryptionStrategy { <<Interface>> +encrypt(String, String) String +decrypt(String, String) String } class AESStrategy { +encrypt(String, String) String +decrypt(String, String) String } class SM4Strategy { +encrypt(String, String) String +decrypt(String, String) String } class AnnotationPackage { +@EnableEncryption +@DisableEncryption } EncryptionAdvice ..> AnnotationPackage : 检查加密注解 EncryptionAdvice ..> EncryptionStrategy : 使用加密策略 EncryptionStrategy <|.. AESStrategy EncryptionStrategy <|.. SM4Strategy ``` #### 1. 核心组件定义 **加密响应体结构:** ```java /** * 加密响应结构 * @param ciphertext Base64编码的加密数据 * @param algorithm 使用的加密算法标识 */ public record EncryptedResponse(String ciphertext, String algorithm) { } ``` **加密策略接口:** ```java public interface EncryptionStrategy { /** * 加密数据 * @param plaintext 明文数据 * @param secretKey 密钥 * @return Base64编码的加密数据 */ String encrypt(String plaintext, String secretKey); /** * 解密数据 * @param ciphertext Base64编码的加密数据 * @param secretKey 密钥 * @return 解密后的明文数据 */ String decrypt(String ciphertext, String secretKey); } ``` #### 2. 加密算法实现 **AES加密策略:** ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class AESStrategy implements EncryptionStrategy { private static final String ALGORITHM = "AES/ECB/PKCS5Padding"; private static final String CHARSET = "UTF-8"; @Override public String encrypt(String plaintext, String secretKey) { try { SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES"); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = cipher.doFinal(plaintext.getBytes(CHARSET)); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new EncryptionException("AES加密失败", e); } } @Override public String decrypt(String ciphertext, String secretKey) { try { SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES"); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, keySpec); byte[] decoded = Base64.getDecoder().decode(ciphertext); byte[] decrypted = cipher.doFinal(decoded); return new String(decrypted, CHARSET); } catch (Exception e) { throw new EncryptionException("AES解密失败", e); } } } ``` **国密SM4加密策略:** ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.security.Security; import java.util.Base64; public class SM4Strategy implements EncryptionStrategy { static { Security.addProvider(new BouncyCastleProvider()); } @Override public String encrypt(String plaintext, String secretKey) { try { SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "SM4"); Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encrypted = cipher.doFinal(plaintext.getBytes("UTF-8")); return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new EncryptionException("SM4加密失败", e); } } @Override public String decrypt(String ciphertext, String secretKey) { try { SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "SM4"); Cipher cipher = Cipher.getInstance("SM4/ECB/PKCS5Padding", "BC"); cipher.init(Cipher.DECRYPT_MODE, keySpec); byte[] decoded = Base64.getDecoder().decode(ciphertext); byte[] decrypted = cipher.doFinal(decoded); return new String(decrypted, "UTF-8"); } catch (Exception e) { throw new EncryptionException("SM4解密失败", e); } } } ``` #### 3. 注解定义 ```java import java.lang.annotation.*; /** * 启用响应加密注解 * @param algorithm 加密算法(默认AES) * @param keyAlias 密钥别名(用于密钥管理) */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EnableEncryption { String algorithm() default "AES"; String keyAlias() default "default"; } /** * 禁用响应加密注解(优先级高于@EnableEncryption) */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface DisableEncryption {} ``` #### 4. ControllerAdvice实现 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @ControllerAdvice public class EncryptionAdvice implements ResponseBodyAdvice<Object> { @Autowired private KeyManager keyManager; // 密钥管理服务 @Autowired private EncryptionStrategyFactory strategyFactory; // 检查是否支持加密处理 @Override public boolean supports(MethodParameter returnType, Class converterType) { // 检查是否标记了禁用加密 if (returnType.hasMethodAnnotation(DisableEncryption.class) || returnType.getContainingClass().isAnnotationPresent(DisableEncryption.class)) { return false; } // 检查是否标记了启用加密 return returnType.hasMethodAnnotation(EnableEncryption.class) || returnType.getContainingClass().isAnnotationPresent(EnableEncryption.class); } // 响应体加密处理 @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 1. 获取加密配置 EnableEncryption config = getEncryptionConfig(returnType); // 2. 序列化响应体为JSON String jsonBody = JsonUtils.toJson(body); // 3. 获取密钥 String secretKey = keyManager.getKey(config.keyAlias()); // 4. 选择加密策略 EncryptionStrategy strategy = strategyFactory.getStrategy(config.algorithm()); // 5. 执行加密 String ciphertext = strategy.encrypt(jsonBody, secretKey); // 6. 返回加密响应结构 return new EncryptedResponse(ciphertext, config.algorithm()); } // 获取加密配置(方法级优先于类级) private EnableEncryption getEncryptionConfig(MethodParameter returnType) { if (returnType.hasMethodAnnotation(EnableEncryption.class)) { return returnType.getMethodAnnotation(EnableEncryption.class); } return returnType.getContainingClass().getAnnotation(EnableEncryption.class); } } // 加密策略工厂 @Component public class EncryptionStrategyFactory { private final Map<String, EncryptionStrategy> strategies = new ConcurrentHashMap<>(); public EncryptionStrategyFactory() { // 注册内置加密策略 registerStrategy("AES", new AESStrategy()); registerStrategy("SM4", new SM4Strategy()); } public void registerStrategy(String algorithm, EncryptionStrategy strategy) { strategies.put(algorithm.toUpperCase(), strategy); } public EncryptionStrategy getStrategy(String algorithm) { EncryptionStrategy strategy = strategies.get(algorithm.toUpperCase()); if (strategy == null) { throw new UnsupportedEncryptionAlgorithmException("不支持的加密算法: " + algorithm); } return strategy; } } // 密钥管理器 @Component public class KeyManager { @Value("${encryption.keys.default:A2B4C6D8E0F2H4J6}") private String defaultKey; private final Map<String, String> keyStore = new ConcurrentHashMap<>(); public KeyManager() { // 初始化默认密钥 keyStore.put("default", defaultKey); } public void addKey(String alias, String key) { keyStore.put(alias, key); } public String getKey(String alias) { String key = keyStore.get(alias); if (key == null) { throw new KeyNotFoundException("未找到密钥别名: " + alias); } return key; } } ``` #### 5. 控制器使用示例 ```java @RestController @RequestMapping("/api") @EnableEncryption(algorithm = "SM4", keyAlias = "user-data") // 类级加密配置 public class SecureController { // 使用类级加密配置 @GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { return userService.getUserById(id); } // 方法级覆盖加密配置 @EnableEncryption(algorithm = "AES", keyAlias = "sensitive-data") @GetMapping("/payment/{id}") public PaymentDetail getPaymentDetail(@PathVariable Long id) { return paymentService.getDetail(id); } // 禁用加密 @DisableEncryption @GetMapping("/public/info") public PublicInfo getPublicInfo() { return infoService.getPublicInfo(); } // 接收加密请求体 @PostMapping("/secure-update") public ResponseEntity<?> updateUser( @RequestBody @EncryptedRequest(algorithm = "SM4", keyAlias = "user-data") User user) { userService.updateUser(user); return ResponseEntity.ok().build(); } } ``` #### 6. 加密请求体处理(可选) ```java @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface EncryptedRequest { String algorithm() default "AES"; String keyAlias() default "default"; } @ControllerAdvice public class DecryptionAdvice implements RequestBodyAdvice { @Autowired private KeyManager keyManager; @Autowired private EncryptionStrategyFactory strategyFactory; @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return methodParameter.hasParameterAnnotation(EncryptedRequest.class); } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { try { // 1. 读取加密请求体 String encrypted = StreamUtils.copyToString(inputMessage.getBody(), StandardCharsets.UTF_8); // 2. 获取解密配置 EncryptedRequest config = parameter.getParameterAnnotation(EncryptedRequest.class); // 3. 获取密钥 String secretKey = keyManager.getKey(config.keyAlias()); // 4. 选择解密策略 EncryptionStrategy strategy = strategyFactory.getStrategy(config.algorithm()); // 5. 解密数据 String decrypted = strategy.decrypt(encrypted, secretKey); // 6. 创建新的输入流 return new DecryptedHttpInputMessage( new ByteArrayInputStream(decrypted.getBytes(StandardCharsets.UTF_8)), inputMessage.getHeaders() ); } catch (IOException e) { throw new DecryptionException("请求体解密失败", e); } } // 其他方法实现... } // 自定义HTTP输入消息 class DecryptedHttpInputMessage implements HttpInputMessage { private final InputStream body; private final HttpHeaders headers; public DecryptedHttpInputMessage(InputStream body, HttpHeaders headers) { this.body = body; this.headers = headers; } @Override public InputStream getBody() { return body; } @Override public HttpHeaders getHeaders() { return headers; } } ``` #### 7. 安全增强配置 **密钥轮换策略:** ```java @Configuration @EnableScheduling public class KeyRotationConfig { @Autowired private KeyManager keyManager; // 每天凌晨轮换密钥 @Scheduled(cron = "0 0 0 * * ?") public void rotateKeys() { String newKey = generateSecureKey(); keyManager.addKey("previous", keyManager.getKey("default")); keyManager.addKey("default", newKey); } private String generateSecureKey() { SecureRandom random = new SecureRandom(); byte[] key = new byte[16]; // 128-bit key random.nextBytes(key); return Base64.getEncoder().encodeToString(key); } } ``` **响应安全头配置:** ```java @Bean public WebMvcConfigurer securityHeadersConfigurer() { return new WebMvcConfigurer() { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { // 添加安全相关HTTP头 response.setHeader("Content-Security-Policy", "default-src 'self'"); response.setHeader("X-Content-Type-Options", "nosniff"); response.setHeader("X-Frame-Options", "DENY"); } }); } }; } ``` #### 8. 客户端交互示例 **请求加密数据:** ```http POST /api/secure-update HTTP/1.1 Content-Type: application/json X-Encryption-Algorithm: SM4 o5YyV6vMx7fO...(SM4加密后的数据) ``` **接收加密响应:** ```json { "ciphertext": "jf8S7dKk3Lm9...", "algorithm": "SM4" } ``` **客户端解密处理:** ```javascript // 前端解密示例(使用CryptoJS) async function decryptResponse(response) { const { ciphertext, algorithm } = await response.json(); const secretKey = await getKeyFromSecureStorage(); let decrypted; if (algorithm === 'AES') { decrypted = CryptoJS.AES.decrypt(ciphertext, secretKey).toString( CryptoJS.enc.Utf8 ); } else { // 处理其他算法... } return JSON.parse(decrypted); } ``` ### 性能优化建议 1. **算法加速:** ```java // 使用硬件加速的AES实现 public AESStrategy() { Security.setProperty("crypto.policy", "unlimited"); } ``` 2. **响应缓存:** ```java @Override public Object beforeBodyWrite(/*参数*/) { String cacheKey = "encrypted_" + body.hashCode(); EncryptedResponse cached = cache.get(cacheKey); if (cached != null) return cached; // ...正常加密逻辑 cache.put(cacheKey, encryptedResponse); return encryptedResponse; } ``` 3. **异步加密:** ```java @Override public Object beforeBodyWrite(/*参数*/) { if (body instanceof CompletableFuture) { return ((CompletableFuture<?>) body).thenApplyAsync(data -> { return encryptData(data, config, secretKey, strategy); }); } return encryptData(body, config, secretKey, strategy); } ``` 4. **批量处理优化:** ```java // 对列表数据分块加密 List<Object> encryptedList = Collections.synchronizedList(new ArrayList<>()); ExecutorService executor = Executors.newFixedThreadPool(4); for (Object item : dataList) { executor.submit(() -> { encryptedList.add(strategy.encrypt(item, secretKey)); }); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES); ``` ### 最佳实践场景 1. **敏感数据保护:** ```java @EnableEncryption(algorithm = "AES", keyAlias = "pii-key") @GetMapping("/user/personal-info") public PersonalInfo getPersonalInfo() { // 返回身份证号、手机号等敏感信息 } ``` 2. **合规性要求:** ```java // 金融类数据使用国密算法 @EnableEncryption(algorithm = "SM4", keyAlias = "finance-key") @GetMapping("/financial/transactions") public List<Transaction> getTransactions() { // 返回金融交易记录 } ``` 3. **动态密钥管理:** ```java @GetMapping("/dynamic-key") @EnableEncryption(keyAlias = "#{@keyManager.getSessionKey(request)}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JB091

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值