• 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));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

    返回参数加密

    @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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    ELK+Filebeat+zookeeper+Kafka原理和搭建
    Logback日志配置
    Koordinator 协同 containerd NRI 增强容器 QoS,提升应用性能
    Flutter 上架如何解决 ITMS-91053 问题
    Elasticsearch的基本介绍
    凯撒密码-加密
    验证周期--一个结构化的流程
    独立站品牌出海盛行,大批卖家转型逐利
    重生的 SDN?我们以前没试过吗?
    java--07 面向对象
  • 原文地址:https://blog.csdn.net/qq_32118691/article/details/133745266