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;
    }
}
相关推荐
亚林瓜子1 天前
AWS中国区中API Gateway中403的AccessDeniedException问题
云计算·gateway·api·aws
blammmp3 天前
Spring Cloud:Gateway(统一服务入口)
spring·spring cloud·gateway
Nerd Nirvana4 天前
网关GateWay——连接不同网络的关键设备
网络·mqtt·计算机网络·gateway·路由器·modbus·电力设备
Paran-ia4 天前
【2025版】SpringCloud Gateway网关快速入门
spring·spring cloud·gateway
泽济天下6 天前
【工作记录】Kong Gateway入门篇之简介
gateway·kong
SHUIPING_YANG6 天前
Nginx 返回 504 状态码表示 网关超时(Gateway Timeout)原因排查
运维·nginx·gateway
Volunteer Technology8 天前
SpringCloud Gateway知识点整理和全局过滤器实现
spring·spring cloud·gateway
matrixlzp8 天前
K8S Gateway AB测试、蓝绿发布、金丝雀(灰度)发布
kubernetes·gateway·ab测试
泽济天下9 天前
【工作记录】Kong Gateway 入门篇之部署及简单测试
gateway·kong
JAVA坚守者10 天前
API 网关核心功能解析:负载均衡、容灾、削峰降级原理与实战摘要
gateway·负载均衡·微服务架构·容灾备份·api 网关·削峰降级·云原生技术