将加解密逻辑封装成通用、可配置、解耦的组件 ,核心是遵循「开闭原则+模板方法+拦截器/中间件模式」,让业务代码无需嵌入加密逻辑,仅通过注解/配置指定需要加密的接口/字段即可。以下是落地方案,以Java Spring Boot(主流企业级框架)为例,同时兼容Go/Python等语言的核心思路。
一、通用组件设计核心原则
- 完全解耦:加密逻辑与业务代码隔离,业务侧仅需「声明式配置」(注解/yml),无需写任何加密代码;
- 可配置化:支持指定「哪些接口、哪些字段」加密/解密,支持切换算法(AES-GCM/ECC/RSA)、密钥来源(KMS/HSM/本地);
- 易扩展:新增加密算法/加密规则时,无需修改核心组件,仅需扩展接口;
- 高性能:组件内部封装对象池、硬件加速、异步处理,对业务透明;
- 可监控:内置加解密耗时、失败率监控,便于排查问题。
二、通用组件分层架构(解耦核心)
组件分为5层,每层职责单一,通过依赖注入解耦:
css
┌─────────────────────────────────────────────────────────┐
│ 业务层(Controller/Service) │
│ (仅加注解/配置,无加密代码) │
└───────────────────┬─────────────────────────────────────┘
│
┌───────────────────▼─────────────────────────────────────┐
│ 接入层(拦截器/过滤器/Middleware) │
│ (拦截请求/响应,触发加解密,对业务透明) │
└───────────────────┬─────────────────────────────────────┘
│
┌───────────────────▼─────────────────────────────────────┐
│ 核心服务层(CryptoTemplate) │
│ (封装通用加解密/签名验签流程,模板方法) │
└───────────────────┬─────────────────────────────────────┘
│
┌───────────────────▼─────────────────────────────────────┐
│ 基础设施层(AlgorithmFactory + KeyManager) │
│ (封装算法、密钥管理,屏蔽底层细节) │
└───────────────────┬─────────────────────────────────────┘
│
┌───────────────────▼─────────────────────────────────────┐
│ 配置/注解层(@Encrypt + yml配置) │
│ (指定加密规则:接口、字段、算法、密钥) │
└─────────────────────────────────────────────────────────┘
三、核心模块实现(Spring Boot版通用组件)
以下是可直接落地的核心代码,聚焦「解耦+通用」,屏蔽复杂的算法细节,业务侧仅需简单配置。
1. 第一步:定义配置/注解(业务侧仅需接触这层)
(1)自定义注解(标记需要加密的接口/字段)
java
/**
* 接口级注解:标记该接口需要加密入参、解密出参
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiEncrypt {
// 加密算法(默认AES-GCM)
String algorithm() default "AES-GCM";
// 密钥标识(关联yml中的密钥配置)
String keyId() default "pay_default_key";
// 是否验签(默认开启)
boolean verifySign() default true;
}
/**
* 字段级注解:标记DTO中的敏感字段,仅加密这些字段
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveField {
// 字段描述(非必需,用于日志)
String desc() default "";
}
(2)yml配置(算法、密钥、超时等)
yaml
crypto:
# 全局配置
global:
algorithm: AES-GCM # 默认算法
timeout: 1000ms # 加解密超时
enable-hardware-accel: true # 开启硬件加速
# 密钥配置(支持KMS/HSM,此处简化为本地配置,生产需替换为KMS)
keys:
pay_default_key:
type: ECC # 密钥类型(ECC/RSA/AES)
public-key: "xxx" # 服务端公钥(客户端用)
private-key: "xxx" # 服务端私钥(服务端用)
expire: 90d # 密钥轮换周期
# 忽略加密的字段(全局)
ignore-fields:
- "orderId"
- "merchantId"
- "timestamp"
2. 第二步:基础设施层(封装算法+密钥,对业务透明)
(1)算法工厂(统一封装算法,支持扩展)
java
/**
* 算法工厂:根据配置动态创建加解密器,屏蔽算法细节
*/
@Component
public class AlgorithmFactory {
@Autowired
private CryptoProperties cryptoProperties;
// 缓存加解密器对象,避免重复创建(性能优化)
private final Map<String, CryptoHandler> handlerCache = new ConcurrentHashMap<>();
/**
* 获取指定算法的加解密器
*/
public CryptoHandler getHandler(String algorithm, String keyId) {
String cacheKey = algorithm + "_" + keyId;
if (handlerCache.containsKey(cacheKey)) {
return handlerCache.get(cacheKey);
}
// 根据算法类型创建对应处理器(策略模式)
CryptoHandler handler = switch (algorithm) {
case "AES-GCM" -> new AesGcmHandler(cryptoProperties.getKeys().get(keyId));
case "ECC" -> new EccHandler(cryptoProperties.getKeys().get(keyId));
case "RSA" -> new RsaHandler(cryptoProperties.getKeys().get(keyId));
default -> throw new CryptoException("不支持的算法:" + algorithm);
};
handlerCache.put(cacheKey, handler);
return handler;
}
// 加解密器接口(扩展新算法只需实现此接口)
public interface CryptoHandler {
// 加密数据
byte[] encrypt(byte[] data, String keyId);
// 解密数据
byte[] decrypt(byte[] data, String keyId);
// 签名
String sign(byte[] data, String keyId);
// 验签
boolean verifySign(byte[] data, String sign, String keyId);
}
// AES-GCM实现(示例,其余算法同理)
public static class AesGcmHandler implements CryptoHandler {
private final KeyConfig keyConfig;
// 缓存Cipher对象(性能优化)
private final ObjectPool<Cipher> cipherPool;
public AesGcmHandler(KeyConfig keyConfig) {
this.keyConfig = keyConfig;
// 初始化Cipher对象池
this.cipherPool = new GenericObjectPool<>(new CipherPooledFactory("AES/GCM/NoPadding"));
}
@Override
public byte[] encrypt(byte[] data, String keyId) {
try (PooledObject<Cipher> pooledCipher = cipherPool.borrowObject()) {
Cipher cipher = pooledCipher.getObject();
// 省略AES-GCM加密逻辑(复用之前的代码)
return cipher.doFinal(data);
} catch (Exception e) {
throw new CryptoException("AES加密失败", e);
}
}
@Override
public byte[] decrypt(byte[] data, String keyId) {
// 同理,省略解密逻辑
return new byte[0];
}
@Override
public String sign(byte[] data, String keyId) {
// 省略签名逻辑
return "";
}
@Override
public boolean verifySign(byte[] data, String sign, String keyId) {
// 省略验签逻辑
return true;
}
}
}
(2)密钥管理器(统一管理密钥,支持KMS/HSM)
typescript
/**
* 密钥管理器:统一获取密钥(本地/KMS/HSM),对上层透明
*/
@Component
public class KeyManager {
@Autowired
private CryptoProperties cryptoProperties;
// 对接KMS的客户端(生产环境用)
@Autowired(required = false)
private KmsClient kmsClient;
/**
* 获取密钥(优先从KMS获取,本地为兜底)
*/
public String getKey(String keyId) {
KeyConfig keyConfig = cryptoProperties.getKeys().get(keyId);
if (keyConfig == null) {
throw new CryptoException("密钥配置不存在:" + keyId);
}
// 生产环境:从KMS/HSM获取密钥
if ("KMS".equals(keyConfig.getType())) {
return kmsClient.getSecret(keyId);
}
// 测试环境:本地配置(生产禁用)
return keyConfig.getPrivateKey();
}
}
3. 第三步:核心服务层(模板方法封装通用流程)
scss
/**
* 加解密模板:封装通用流程,拦截器直接调用,无需重复写逻辑
*/
@Service
public class CryptoTemplate {
@Autowired
private AlgorithmFactory algorithmFactory;
@Autowired
private KeyManager keyManager;
/**
* 通用加密流程:加密敏感字段 + 签名
*/
public <T> T encrypt(T data, String algorithm, String keyId) {
try {
// 1. 获取算法处理器
AlgorithmFactory.CryptoHandler handler = algorithmFactory.getHandler(algorithm, keyId);
// 2. 反射获取@SensitiveField字段,仅加密这些字段
Field[] fields = data.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SensitiveField.class)) {
field.setAccessible(true);
Object value = field.get(data);
if (value != null) {
// 3. 加密敏感字段
byte[] encrypted = handler.encrypt(value.toString().getBytes(), keyId);
field.set(data, Base64.getEncoder().encodeToString(encrypted));
}
}
}
// 4. 签名(可选)
String sign = handler.sign(JsonUtil.toJsonBytes(data), keyId);
// 给DTO设置签名(假设DTO有sign字段)
Field signField = data.getClass().getDeclaredField("sign");
signField.setAccessible(true);
signField.set(data, sign);
return data;
} catch (Exception e) {
throw new CryptoException("加密失败", e);
}
}
/**
* 通用解密流程:验签 + 解密敏感字段
*/
public <T> T decrypt(T data, String algorithm, String keyId) {
try {
AlgorithmFactory.CryptoHandler handler = algorithmFactory.getHandler(algorithm, keyId);
// 1. 验签
Field signField = data.getClass().getDeclaredField("sign");
signField.setAccessible(true);
String sign = (String) signField.get(data);
if (!handler.verifySign(JsonUtil.toJsonBytes(data), sign, keyId)) {
throw new CryptoException("验签失败");
}
// 2. 解密敏感字段
Field[] fields = data.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(SensitiveField.class)) {
field.setAccessible(true);
String encryptedValue = (String) field.get(data);
if (encryptedValue != null) {
byte[] decrypted = handler.decrypt(Base64.getDecoder().decode(encryptedValue), keyId);
field.set(data, new String(decrypted));
}
}
}
return data;
} catch (Exception e) {
throw new CryptoException("解密失败", e);
}
}
}
4. 第四步:接入层(拦截器,自动处理请求/响应)
java
/**
* 加解密拦截器:拦截@ApiEncrypt注解的接口,自动处理加解密
*/
@Component
public class CryptoInterceptor implements HandlerInterceptor {
@Autowired
private CryptoTemplate cryptoTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 判断是否是Controller方法,且有@ApiEncrypt注解
if (handler instanceof HandlerMethod handlerMethod) {
ApiEncrypt apiEncrypt = handlerMethod.getMethodAnnotation(ApiEncrypt.class);
if (apiEncrypt != null) {
// 2. 读取请求体
String requestBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
// 3. 反序列化为DTO(需获取方法入参类型)
Class<?> paramType = handlerMethod.getMethod().getParameterTypes()[0];
Object dto = JsonUtil.fromJson(requestBody, paramType);
// 4. 解密DTO(自动处理敏感字段)
Object decryptedDto = cryptoTemplate.decrypt(dto, apiEncrypt.algorithm(), apiEncrypt.keyId());
// 5. 替换请求体为解密后的数据(让Controller拿到明文)
request.setAttribute("decryptedParam", decryptedDto);
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 1. 判断是否有@ApiEncrypt注解
if (handler instanceof HandlerMethod handlerMethod) {
ApiEncrypt apiEncrypt = handlerMethod.getMethodAnnotation(ApiEncrypt.class);
if (apiEncrypt != null) {
// 2. 获取Controller返回的响应体(需结合ResponseBodyAdvice)
// 此处简化,实际用ResponseBodyAdvice拦截响应更优雅
Object responseBody = request.getAttribute("responseBody");
// 3. 加密响应体(自动处理敏感字段)
Object encryptedBody = cryptoTemplate.encrypt(responseBody, apiEncrypt.algorithm(), apiEncrypt.keyId());
// 4. 写入加密后的响应
response.getWriter().write(JsonUtil.toJson(encryptedBody));
}
}
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CryptoInterceptor cryptoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(cryptoInterceptor)
.addPathPatterns("/api/pay/**") // 仅拦截支付相关接口
.excludePathPatterns("/api/public/**"); // 排除公开接口
}
}
5. 第五步:业务侧使用(极简,无加密代码)
(1)定义DTO(仅标记敏感字段)
typescript
// 支付请求DTO
public class PayRequestDTO {
// 非敏感字段,无需加密
private String orderId;
private String merchantId;
private Long timestamp;
// 签名字段(自动生成/验证)
private String sign;
// 敏感字段,标记后自动加密/解密
@SensitiveField(desc = "银行卡号")
private String cardNo;
@SensitiveField(desc = "CVV码")
private String cvv;
@SensitiveField(desc = "支付金额")
private String amount;
// getter/setter
}
(2)Controller(仅加注解,无加密逻辑)
less
@RestController
@RequestMapping("/api/pay")
public class PayController {
@Autowired
private PayService payService;
// 仅需加@ApiEncrypt注解,自动解密入参、加密出参
@PostMapping("/submit")
@ApiEncrypt(algorithm = "AES-GCM", keyId = "pay_default_key")
public PayResponseDTO submitPay(@RequestBody PayRequestDTO request) {
// 业务逻辑:直接使用明文request,无需任何加密代码
return payService.submit(request);
}
}
四、通用组件的扩展与适配
1. 适配其他框架/语言
- Go语言 :将拦截器改为HTTP中间件(
http.HandlerFunc),注解改为配置文件(如crypto.yaml指定接口规则),核心算法工厂/模板逻辑一致; - Python :用Django/Flask的中间件(Middleware)替代拦截器,装饰器替代注解,核心逻辑封装为
crypto模块; - 微服务场景:将组件封装为SDK,各服务引入SDK后仅需配置,无需重复开发。
2. 扩展新算法
只需实现AlgorithmFactory.CryptoHandler接口,无需修改核心代码:
typescript
// 新增SM4算法(国密)
public static class Sm4Handler implements AlgorithmFactory.CryptoHandler {
@Override
public byte[] encrypt(byte[] data, String keyId) {
// SM4加密逻辑
return new byte[0];
}
// 实现其他方法...
}
3. 性能优化(组件内置)
- 对象池:缓存Cipher、Signature等重量级对象,避免频繁创建;
- 异步处理:加解密耗时较长时,用CompletableFuture异步处理;
- 硬件加速:在AlgorithmFactory中自动开启AES-NI/SHA指令集;
- 批量处理:支持批量接口的加解密,减少多次调用开销。
五、生产环境落地注意事项
- 密钥管理:生产环境禁止本地配置密钥,必须对接KMS/HSM,KeyManager中封装KMS调用逻辑;
- 异常处理 :组件内置统一的加密异常(
CryptoException),全局异常处理器捕获后返回标准化错误码; - 监控告警:埋点加解密耗时、失败率,超过阈值(如1ms)告警;
- 兼容性:支持部分接口不加密(通过注解/配置排除),兼容老接口平滑迁移;
- 测试:组件单独写单元测试(覆盖所有算法、异常场景),业务侧仅需测试业务逻辑。
总结
通用加解密组件的核心是「拦截器+模板方法+配置驱动」:
- 业务侧:仅需加注解/配置,完全脱离加密细节;
- 组件侧:封装所有加密逻辑,算法/密钥/规则可配置、可扩展;
- 性能:组件内部做对象池、硬件加速等优化,对业务透明。
按此方案实现后,新增需要加密的接口时,仅需:
- 在DTO的敏感字段加
@SensitiveField; - 在Controller方法加
@ApiEncrypt; - 在yml中配置密钥(如需)。
完全解耦业务与加密逻辑,符合企业级「高内聚、低耦合」的设计规范。