gateway接口参数加解密

上篇介绍了多种加解密的使用java加密使用

本篇主要介绍在gateway网关中使用对参数解密和返回数据进行加密的操作

原理

下面使用的是AES加密 SHA1withRSA加签

1-用户使用拿到的AES秘钥和RSA私钥。对数据进行加密和加签

2-进行验签和时间的检验

3-将解密的数据返回到具体的调用方(通过特定的filter具体业务方是无感知加解密的)

4-将业务方数据加密返回给调用方

参数校验

java 复制代码
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
@Component
public class SignatureValidationGatewayFilterFactory extends AbstractGatewayFilterFactory {

    private final EtrGatewayProperties etrGatewayProperties;

    @Autowired
    public SignatureValidationGatewayFilterFactory(EtrGatewayProperties etrGatewayProperties) {
        this.etrGatewayProperties = etrGatewayProperties;
    }

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            if (HttpMethod.GET.matches(exchange.getRequest().getMethodValue())
                    || HttpMethod.POST.matches(exchange.getRequest().getMethodValue())) {
                ModifyRequestBodyGatewayFilterFactory.Config modifyRequestConfig = new ModifyRequestBodyGatewayFilterFactory.Config()
                        .setContentType(ContentType.APPLICATION_JSON.getMimeType())
                        .setRewriteFunction(String.class, String.class, (exchange1, originalRequestBody) -> {
                            try {
                                JSONObject jsonObject = JSONUtil.parseObj(originalRequestBody);
                                String appId = jsonObject.getStr(SignatureConstants.SIGN_APPID);
                                String sign = jsonObject.getStr(SignatureConstants.SIGN_KEY);
                                String signType = jsonObject.getStr(SignatureConstants.SIGN_TYPE);
                                String timeStamp = jsonObject.getStr(SignatureConstants.SIGN_TIME_STAMP);
                                EtrGatewayProperties.SinatureConfig first = etrGatewayProperties.getSignatures().stream()
                                        .filter(appConfig -> appConfig.getAppId().equalsIgnoreCase(appId))
                                        .findFirst().orElse(null);
                                if (Objects.isNull(first)) {
                                    log.error("appId:{}不合法", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }
                                if (StrUtil.isBlank(sign) || StrUtil.isBlank(signType) || !StrUtil.isNumeric(timeStamp)) {
                                    log.error("参数不合法:sign:{},signType:{},timestamp:{}", sign, signType, timeStamp);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                // 验证时间戳
                                if (!validateTimestamp(timeStamp, first)) {
                                    log.warn("Invalid timestamp for appId: {}", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                // 验证签名
                                if (!validateSignature(jsonObject, appId, signType, sign, first)) {
                                    log.warn("Signature verification failed for appId: {}", appId);
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                String dataStr = decryptData(jsonObject.getStr(SignatureConstants.SIGN_DATA), first.getAesKey());

                                if (StringUtils.isBlank(dataStr)) {
                                    return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                                }

                                exchange1.getRequest().mutate().header(SignatureConstants.SIGN_APPID, appId);
                                return Mono.just(dataStr);
                            } catch (Exception e) {
                                return Mono.error(e);
                            }
                        });

                return new ModifyRequestBodyGatewayFilterFactory()
                        .apply(modifyRequestConfig)
                        .filter(exchange, chain)
                        .onErrorResume(e -> handleFilterError(exchange, e));
            }

            return chain.filter(exchange);
        };
    }

    private boolean validateTimestamp(String timeStamp, EtrGatewayProperties.SinatureConfig appConfig) {
        Integer timestampExpire = Optional.ofNullable(appConfig.getTimeStampExpire()).orElse(300);
        DateTime time = DateUtil.parse(timeStamp, DateUtil.newSimpleFormat("yyyyMMddHHmmss"));
        long between = DateUtil.between(time, new Date(), DateUnit.SECOND);
        return Math.abs(between) <= timestampExpire;
    }

    private boolean validateSignature(JSONObject jsonObject, String appId, String signType, String sign, EtrGatewayProperties.SinatureConfig appConfig) {
        String publicKey = appConfig.getPublicKey();
        SignStrategy signStrategy = new DefaultSignStrategy();
        try {
            return signStrategy.verifyPost(jsonObject.getStr(SignatureConstants.SIGN_DATA), publicKey,
                    CipherType.valueOf(signType.toUpperCase()), sign);
        } catch (Exception e) {
            log.error("Signature verification failed for appId: {}", appId, e);
            return false;
        }
    }

    private String decryptData(String data, String aesKey) {
        AES aes = SecureUtil.aes(aesKey.getBytes());
        return aes.decryptStr(data);
    }

    private Mono<Void> handleFilterError(ServerWebExchange exchange, Throwable e) {
        if (e instanceof BizException) {
            log.error("Filter error: {}", e.getMessage());
            return signatureError(exchange);
        }
        return Mono.error(e);
    }

    private Mono<Void> signatureError(ServerWebExchange exchange) {
        log.warn("Signature error: {}", exchange.getRequest().getURI().getPath());
        ApiResult<Object> result = ApiResult.fail(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        DataBuffer buffer = response.bufferFactory().wrap(JSONUtil.toJsonStr(result).getBytes());
        return response.writeWith(Mono.just(buffer)).then(Mono.defer(response::setComplete));
    }
}

返回参数加密

java 复制代码
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
@Component
public class SignatureResGatewayFilterFactory extends ModifyResponseBodyGatewayFilterFactory {

    private final EtrGatewayProperties etrGatewayProperties;

    public SignatureResGatewayFilterFactory(ServerCodecConfigurer codecConfigurer, Set<MessageBodyDecoder> bodyDecoders,
                                            Set<MessageBodyEncoder> bodyEncoders, EtrGatewayProperties etrGatewayProperties) {
        super(codecConfigurer.getReaders(), bodyDecoders, bodyEncoders);
        this.etrGatewayProperties = etrGatewayProperties;
    }

    @Override
    public GatewayFilter apply(Config config) {
        config.setRewriteFunction(String.class, String.class, (serverWebExchange, s) -> {
            JSONObject resJson = JSONUtil.parseObj(s);
            Integer code = resJson.getInt("code");
            if (200 == code) {
                String dataStr = resJson.getStr("data");
                if (StrUtil.isNotBlank(dataStr)) {
                    String appId = serverWebExchange.getRequest().getHeaders().getFirst(SignatureConstants.SIGN_APPID);
                    if (StrUtil.isBlank(appId)) {
                        return Mono.error(BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR));
                    }
                    AES aes = SecureUtil.aes(getAesKey(appId).getBytes());
                    resJson.set("data", aes.encryptBase64(dataStr));
                    return Mono.just(resJson.toString());
                }
            }
            return Mono.just(s);

        });
        ModifyResponseGatewayFilter gatewayFilter = new ModifyResponseGatewayFilter(config);
        gatewayFilter.setFactory(this);
        return gatewayFilter;
    }

    private String getAesKey(String appId) {
        EtrGatewayProperties.SinatureConfig first = etrGatewayProperties.getSignatures().stream()
                .filter(appConfig -> appConfig.getAppId().equalsIgnoreCase(appId))
                .findFirst().orElse(null);
        if (Objects.isNull(first)) {
            throw BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        }

        String aesKey = first.getAesKey();
        if (StrUtil.isBlank(aesKey)) {
            throw BizException.of(GatewayErrorCodeEnum.SIGNATURE_ERROR);
        }
        return aesKey;
    }
}
相关推荐
码点滴15 小时前
私有 Gateway 接入企业 IM:从消息路由到多租户隔离——Hermes Agent 工程实战
人工智能·架构·gateway·prompt·智能体·hermes
代码写到35岁16 小时前
Gateway+OpenFeign 踩坑总结
gateway
invicinble17 小时前
对于gateway信息量沉淀
gateway
郝开2 天前
Spring Cloud Gateway 3.5.14 使用手册
java·数据库·spring boot·gateway
Ribou3 天前
Kubernetes v1.35.2 基于 Cilium Gateway API 的服务访问架构
架构·kubernetes·gateway
huipeng9264 天前
GateWay使用详解
java·spring boot·spring cloud·微服务·gateway
随风,奔跑7 天前
Spring Cloud Alibaba(四)---Spring Cloud Gateway
后端·spring·gateway
jiayong238 天前
Hermes Agent 的 Skills、Plugins、Gateway 深度解析
ai·gateway·agent·hermes agent·hermes
鬼蛟8 天前
Gateway
gateway
武超杰8 天前
Spring Cloud Gateway 从入门到实战
spring cloud·gateway