gateway接口参数加解密

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

原理

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

1-用户使用拿到的AES秘钥和RSA私钥。对数据进行加密和加签
2-进行验签和时间的检验
3-将解密的数据返回到具体的调用方(通过特定的filter具体业务方是无感知加解密的)
4-将业务方数据加密返回给调用方

参数校验

@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));
    }
}

返回参数加密

@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;
    }
}

你可能感兴趣的:(gateway,接口参数验签解密)