java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot接口数据加解密

SpringBoot实现接口数据加解密的三种实战方案

作者:星辰聊技术

在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,Spring Boot 提供了多种优雅的加解密实现方案,本文将从原理到实战,带你掌握三种主流实现方式,需要的朋友可以参考下

一、为什么需要接口数据加解密?

在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取。例如:

Spring Boot 提供了多种优雅的加解密实现方案,既能保证数据安全,又能最小化业务侵入性。本文将从原理到实战,带你掌握三种主流实现方式。

二、核心加解密算法选择

1. 对称加密(AES)

优势:加密速度快,适合大流量数据传输缺点:密钥需安全存储,适合客户端与服务端一对一场景

// AES 工具类(128位密钥)
public class AESUtils {
    private static final String KEY = "your_16bit_secret_key";
    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
    public static String encrypt(String data) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"));
        return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
    }
    public static String decrypt(String data) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(KEY.getBytes(), "AES"));
        return new String(cipher.doFinal(Base64.getDecoder().decode(data)));
    }
}

2. 非对称加密(RSA)

优势:密钥对机制,适合证书认证场景缺点:加密效率低,通常用于加密对称密钥

// RSA 工具类(生成公钥私钥对)
public class RSAUtils {
    private static final int KEY_SIZE = 1024;
    private static final String ALGORITHM = "RSA";
    public static Map<String, String> generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM);
        generator.initialize(KEY_SIZE);
        KeyPair pair = generator.generateKeyPair();
        return Map.of(
            "publicKey", Base64.getEncoder().encodeToString(pair.getPublic().getEncoded()),
            "privateKey", Base64.getEncoder().encodeToString(pair.getPrivate().getEncoded())
        );
    }
}

三、实战方案一:基于 AOP 的透明加解密

1. 核心原理

通过自定义注解标记需要加解密的接口,利用 Spring AOP 在方法调用前后自动处理加解密逻辑,实现业务代码零侵入。

2. 实现步骤

(1)定义加解密注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
    // 排除字段(如时间戳等无需加密字段)
    String[] excludeFields() default {};
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
    // 解密失败是否抛出异常
    boolean throwOnFailure() default true;
}

(2)编写 AOP 切面

@Aspect
@Component
public class DataEncryptAspect {
    @Around("@annotation(Encrypt)")
    public Object encryptAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 执行原始方法
        Object result = joinPoint.proceed();
        // 对响应结果进行AES加密
        return AESUtils.encrypt(JSON.toJSONString(result));
    }
    @Around("@annotation(Decrypt)")
    public Object decryptAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取请求参数(假设参数为JSON字符串)
        Object[] args = joinPoint.getArgs();
        String encryptedData = (String) args[0];
        // 解密请求参数
        String decryptedData = AESUtils.decrypt(encryptedData);
        // 替换原始参数为解密后的数据
        args[0] = decryptedData;
        return joinPoint.proceed(args);
    }
}

(3)控制器使用示例

@RestController
@RequestMapping("/api")
public class UserController {
    @PostMapping("/register")
    @Decrypt
    public UserRegisterResponse register(@RequestBody String encryptedData) {
        // 处理解密后的明文数据
        UserRegisterRequest request = JSON.parseObject(encryptedData, UserRegisterRequest.class);
        // 业务逻辑...
        return new UserRegisterResponse("注册成功", request.getUserId());
    }
    @GetMapping("/profile")
    @Encrypt
    public UserProfile getProfile(@RequestParam String userId) {
        // 业务逻辑获取用户信息
        return new UserProfile("张三", "138****1234");
    }
}

3. 方案优势

四、实战方案二:全局过滤器实现请求响应加解密

1. 核心原理

通过实现 Filter 或 HandlerInterceptor,在请求进入控制器前解密参数,响应离开前加密结果,实现全局统一加解密。

2. 实现步骤

(1)自定义加解密过滤器

@Component
public class DataEncryptFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        // 处理请求解密(假设请求体为加密的JSON)
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String encryptedBody = IOUtils.toString(httpRequest.getInputStream(), StandardCharsets.UTF_8);
        String decryptedBody = AESUtils.decrypt(encryptedBody);


        // 包装请求体为可重复读取的流
        HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(httpRequest, decryptedBody);


        // 处理响应加密
        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper((HttpServletResponse) response, buffer);


        chain.doFilter(requestWrapper, responseWrapper);


        // 对响应结果加密并写出
        String encryptedResult = AESUtils.encrypt(buffer.toString());
        response.getWriter().write(encryptedResult);
    }
}
// 请求包装类(重写getInputStream)
class HttpServletRequestWrapper extends HttpServletRequestWrapper {
    private final String body;
    public HttpServletRequestWrapper(HttpServletRequest request, String body) {
        super(request);
        this.body = body;
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bis = new ByteArrayInputStream(body.getBytes());
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bis.read();
            }
            // 省略其他抽象方法实现
        };
    }
}

(2)配置过滤器生效

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<DataEncryptFilter> encryptFilterRegistration() {
        FilterRegistrationBean<DataEncryptFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new DataEncryptFilter());
        registration.addUrlPatterns("/api/v1/**"); // 配置需要加解密的接口路径
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 保证过滤器优先执行
        return registration;
    }
}

3. 方案优势

五、实战方案三:自定义 MessageConverter 实现透明加解密

1. 核心原理

重写 Spring MVC 的 HttpMessageConverter,在请求参数解析和响应数据序列化阶段自动完成加解密,与框架深度整合。

2. 实现步骤

(1)自定义加解密转换器

public class EncryptingHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    @Override
    protected boolean supports(Class<?> clazz) {
        return true; // 支持所有类型
    }
    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) 
            throws IOException, HttpMessageNotReadableException {
        // 读取加密的请求体并解密
        String encrypted = IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8);
        String decrypted = AESUtils.decrypt(encrypted);
        return JSON.parseObject(decrypted, clazz);
    }
    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) 
            throws IOException, HttpMessageNotWritableException {
        // 将响应对象加密后写出
        String plain = JSON.toJSONString(object);
        String encrypted = AESUtils.encrypt(plain);
        outputMessage.getBody().write(encrypted.getBytes(StandardCharsets.UTF_8));
    }
}

(2)注册自定义转换器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new EncryptingHttpMessageConverter());
        // 保留默认转换器(可选)
        // converters.addAll(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
    }
}

3. 方案优势

六、三种方案对比与选型建议

方案一:AOP 注解

侵入性:低

性能:中灵

活性:接口级控制

适用场景:部分接口需要加解密

方案二:全局过滤器

侵入性:中性能:高

灵活性:路径级控制

适用场景:前后端分离项目全局加密

方案三:MessageConverter

侵入性:高

性能:最高

灵活性:框架级控制

适用场景:统一请求响应格式场景

七、生产环境最佳实践

1. 密钥管理方案

2. 异常处理机制

@RestControllerAdvice
public class EncryptExceptionHandler {
    @ExceptionHandler(DecryptionException.class)
    public ResponseEntity<String> handleDecryptionError(DecryptionException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body("数据解密失败:" + e.getMessage());
    }
}

3. 性能优化技巧

八、总结

Spring Boot 提供了从接口级到框架级的完整加解密解决方案,核心是根据业务场景选择合适的实现方式:

无论哪种方案,都需注意密钥安全和异常处理。通过本文的源码示例,开发者可快速在项目中落地接口数据加解密功能,在保障数据安全的同时,最小化对现有业务的影响。

以上就是SpringBoot实现接口数据加解密的三种实战方案的详细内容,更多关于SpringBoot接口数据加解密的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文