国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密

這篇具有很好參考價值的文章主要介紹了SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

本文環(huán)境使用比較新的 Java 17 和 SpringBoot 3.1.5,對應(yīng)到Spring的版本是 6.0.13
使用到的三方插件有:

  • lombok
  • gson
  • hutool

本文注重實現(xiàn)請求的解密和響應(yīng)的加密,加解密使用的是 Hutool 中的工具類,加解密算法目前提供了AES的方式,其余方式也可兼容擴展。
完整代碼倉庫:https://gitee.com/fengsoshuai/springcloud-gateway-feng-demo

借用網(wǎng)關(guān)中的過濾器GlobalFilter來實現(xiàn)這一功能。
本文只粘貼一些重點文件內(nèi)容。

正文

一、項目簡介

SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密,web框架學(xué)習(xí),Java特性,spring cloud,gateway,spring boot,請求解密,響應(yīng)加密
在聚合項目中,有兩個核心模塊,feng-server提供了 rest 接口,供網(wǎng)關(guān)使用。
feng-gateway 是核心實現(xiàn)的網(wǎng)關(guān)項目,實現(xiàn)了自定義過濾器,以及增加了一些基本配置功能。本文重心是網(wǎng)關(guān)項目。

二、核心代碼

2.1 自定義過濾器

package org.feng.fenggateway.filters;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.feng.fenggateway.config.SecureProperties;
import org.feng.fenggateway.dto.ResponseDto;
import org.feng.fenggateway.secure.SecureComponent;
import org.feng.fenggateway.secure.SecureComponentFactory;
import org.feng.fenggateway.util.GsonUtil;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Set;

/**
 * 自定義密文過濾器
 *
 * @author feng
 */
@Slf4j
@Component
public class CustomCipherTextFilter implements GlobalFilter, Ordered {

    @Resource
    private SecureProperties secureProperties;

    private SecureComponent secureComponent;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 獲取請求體
        ServerHttpRequest request = exchange.getRequest();
        // 獲取響應(yīng)體
        ServerHttpResponse response = exchange.getResponse();
        // 請求頭
        HttpHeaders headers = request.getHeaders();
        // 請求方法
        HttpMethod method = request.getMethod();

        // 滿足條件,進行過濾
        if (isNeedFilterMethod(method) && isNeedFilterContentType(headers.getContentType())) {
            return DataBufferUtils.join(request.getBody())
                    .flatMap(dataBuffer -> {
                        try {
                            // 獲取請求參數(shù)
                            String originalRequestBody = getOriginalRequestBody(dataBuffer);

                            // 解密請求參數(shù)
                            String decryptRequestBody = decryptRequest(originalRequestBody);

                            // 裝飾新的請求體
                            ServerHttpRequestDecorator requestDecorator = serverHttpRequestDecorator(request, decryptRequestBody);

                            // 裝飾新的響應(yīng)體
                            ServerHttpResponseDecorator responseDecorator = serverHttpResponseDecorator(response);

                            // 使用新的請求和響應(yīng)轉(zhuǎn)發(fā)
                            ServerWebExchange serverWebExchange = exchange.mutate().request(requestDecorator).response(responseDecorator).build();

                            // 放行攔截
                            return chain.filter(serverWebExchange);
                        } catch (Exception e) {
                            log.error("密文過濾器加解密錯誤", e);
                            return Mono.empty();
                        } finally {
                            DataBufferUtils.release(dataBuffer);
                        }
                    });
        }
        return chain.filter(exchange);
    }

    private String decryptRequest(String originalRequestBody) {
        if (!secureProperties.enableDecryptRequestParam()) {
            log.info("請求參數(shù)解密,跳過");
            return originalRequestBody;
        }

        log.info("請求參數(shù)解密,原文:{}", originalRequestBody);
        String decrypted = getSecureComponent().decrypt(originalRequestBody);
        log.info("請求參數(shù)解密,明文:{}", decrypted);
        return decrypted;
    }

    private String encryptResponse(String originalResponseBody) {
        if (!secureProperties.enableEncryptResponseParam()) {
            log.info("響應(yīng)結(jié)果加密,跳過");
            return originalResponseBody;
        }

        ResponseDto responseDto = GsonUtil.fromJson(originalResponseBody, ResponseDto.class);
        // 只對data字段進行加密處理
        Object data = responseDto.getData();
        if (Objects.nonNull(data)) {
            responseDto.setData(getSecureComponent().encrypt(data.toString()));
        }
        log.info("響應(yīng)結(jié)果加密,原文:{}", originalResponseBody);
        String result = GsonUtil.toJson(responseDto);
        log.info("響應(yīng)結(jié)果加密,密文:{}", result);
        return result;
    }

    /**
     * 獲取原始的請求參數(shù)
     *
     * @param dataBuffer 數(shù)據(jù)緩沖
     * @return 原始的請求參數(shù)
     */
    private String getOriginalRequestBody(DataBuffer dataBuffer) {
        byte[] bytes = new byte[dataBuffer.readableByteCount()];
        dataBuffer.read(bytes);
        return new String(bytes, StandardCharsets.UTF_8);
    }


    private boolean isNeedFilterMethod(HttpMethod method) {
        return NEED_FILTER_METHOD_SET.contains(method);
    }

    private boolean isNeedFilterContentType(MediaType mediaType) {
        return NEED_FILTER_MEDIA_TYPE_SET.contains(mediaType) || "json".equals(mediaType.getSubtype());
    }

    private ServerHttpRequestDecorator serverHttpRequestDecorator(ServerHttpRequest originalRequest, String decryptRequestBody) {
        return new ServerHttpRequestDecorator(originalRequest) {
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }

            @Override
            public Flux<DataBuffer> getBody() {
                byte[] bytes = decryptRequestBody.getBytes(StandardCharsets.UTF_8);
                return Flux.just(new DefaultDataBufferFactory().wrap(bytes));
            }
        };
    }


    private ServerHttpResponseDecorator serverHttpResponseDecorator(ServerHttpResponse originalResponse) {
        DataBufferFactory dataBufferFactory = originalResponse.bufferFactory();
        return new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux<? extends DataBuffer> fluxBody) {
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] byteArray = new byte[join.readableByteCount()];
                        join.read(byteArray);
                        DataBufferUtils.release(join);

                        String originalResponseBody = new String(byteArray, StandardCharsets.UTF_8);
                        //加密
                        byte[] encryptedByteArray = encryptResponse(originalResponseBody).getBytes(StandardCharsets.UTF_8);
                        originalResponse.getHeaders().setContentLength(encryptedByteArray.length);
                        originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
                        return dataBufferFactory.wrap(encryptedByteArray);
                    }));
                }
                return super.writeWith(body);
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.putAll(originalResponse.getHeaders());
                return headers;
            }
        };
    }


    private static final Set<HttpMethod> NEED_FILTER_METHOD_SET = Set.of(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT);
    private static final Set<MediaType> NEED_FILTER_MEDIA_TYPE_SET = Set.of(MediaType.APPLICATION_JSON);

    @Override
    public int getOrder() {
        return -1;
    }

    public SecureComponent getSecureComponent() {
        if (Objects.isNull(secureComponent)) {
            secureComponent = SecureComponentFactory.get(secureProperties.getAlgorithm());
        }
        return secureComponent;
    }
}

2.2 網(wǎng)關(guān)配置

server:
  port: 10010 # 網(wǎng)關(guān)端口
spring:
  application:
    name: gateway # 服務(wù)名稱
  cloud:
    gateway:
      routes: # 網(wǎng)關(guān)路由配置
        - id: feng-server1 # 路由id,自定義,只要唯一即可
          uri: http://127.0.0.1:8081 # 路由的目標地址 http就是固定地址
          predicates: # 路由斷言,也就是判斷請求是否符合路由規(guī)則的條件
            - Path=/server/list/server1/** # 這個是按照路徑匹配,只要以/user/開頭就符合要求
        - id: feng-server2
          uri: http://127.0.0.1:8082
          predicates:
            - Path=/server/list/server2/**

# 自定義配置
feng:
  gateway:
    secure:
      request-switch:
        enable: false
      response-switch:
        enable: true
      algorithm: aes

2.3 自定義配置類

package org.feng.fenggateway.config;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.feng.fenggateway.secure.SecureComponentFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Objects;

/**
 * 加解密屬性配置
 *
 * @author feng
 */
@Slf4j
@Data
@ConfigurationProperties(prefix = SecureProperties.SECURE_PROPERTIES_PREFIX)
public class SecureProperties {

    public static final String SECURE_PROPERTIES_PREFIX = "feng.gateway.secure";

    /**
     * 算法
     */
    private SymmetricAlgorithm algorithm;

    /**
     * 請求開關(guān)
     */
    private SecureSwitch requestSwitch;

    /**
     * 響應(yīng)開關(guān)
     */
    private SecureSwitch responseSwitch;

    public void checkSupportedAlgorithm() {
        log.info("校驗是否支持算法:{}", algorithm);
        if (Objects.isNull(algorithm)) {
            return;
        }
        boolean supportedAlgorithm = SecureComponentFactory.isSupportedAlgorithm(algorithm);
        if (!supportedAlgorithm) {
            throw new UnsupportedOperationException("不支持的算法");
        }
        log.info("校驗是否支持算法:校驗通過");
    }

    /**
     * 是否啟用解密請求參數(shù)
     *
     * @return 默認為否,其他情況看配置
     */
    public boolean enableDecryptRequestParam() {
        if (Objects.isNull(requestSwitch)) {
            return false;
        }
        return requestSwitch.getEnable();
    }

    /**
     * 是否啟用加密響應(yīng)參數(shù)
     *
     * @return 默認為否,其他情況看配置
     */
    public boolean enableEncryptResponseParam() {
        if (Objects.isNull(responseSwitch)) {
            return false;
        }
        return responseSwitch.getEnable();
    }
}

2.4 加密組件接口

這個可以用來擴展支持其他加密算法,目前實現(xiàn)類只有AES。

package org.feng.fenggateway.secure;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import jakarta.annotation.PostConstruct;

/**
 * 加解密組件
 *
 * @author feng
 */
public interface SecureComponent {

    /**
     * 加密
     *
     * @param originalText 原文
     * @return 密文
     */
    String encrypt(String originalText);

    /**
     * 解密
     *
     * @param encryptedText 密文
     * @return 解密后的明文
     */
    String decrypt(String encryptedText);

    /**
     * 獲取加解密算法類型
     *
     * @return 加解密算法類型
     */
    SymmetricAlgorithm getAlgorithmType();


    @PostConstruct
    default void registerToFactory() {
        SecureComponentFactory.registerBean(this);
    }
}

2.5 加密組件實現(xiàn),AES算法

package org.feng.fenggateway.secure;

import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;

/**
 * AES加解密組件
 *
 * @author feng
 */
@Component
public class SecureAESComponent implements SecureComponent {

    /**
     * 生成密鑰,16、24、32位都行
     */
    private final static byte[] SECURE_KEY = "r4oz0f3kfk5tgyui".getBytes(StandardCharsets.UTF_8);

    /**
     * 偏移量,必須16位
     */
    private final static String IV = "r21g95kdsd423gy6";

    private final static AES AES_INSTANCE = new AES(Mode.CTS, Padding.PKCS5Padding, SECURE_KEY, IV.getBytes(StandardCharsets.UTF_8));

    @Override
    public String encrypt(String originalText) {
        return AES_INSTANCE.encryptHex(originalText);
    }

    @Override
    public String decrypt(String encryptedText) {
        return AES_INSTANCE.decryptStr(encryptedText);
    }

    @Override
    public SymmetricAlgorithm getAlgorithmType() {
        return SymmetricAlgorithm.AES;
    }
}

2.6 啟動類,校驗支持的算法配置

package org.feng.fenggateway;

import jakarta.annotation.Resource;
import org.feng.fenggateway.config.SecureProperties;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@ConfigurationPropertiesScan
@SpringBootApplication
public class FengGatewayApplication implements CommandLineRunner {

    @Resource
    private SecureProperties secureProperties;

    public static void main(String[] args) {
        SpringApplication.run(FengGatewayApplication.class, args);
    }

    @Override
    public void run(String... args) {
        secureProperties.checkSupportedAlgorithm();
    }
}

三、請求報文示例

POST http://localhost:10010/server/list/server2/user?authorization=feng
Content-Type: application/json;charset=UTF-8

{
  "username": "fbb"
}

四、測試結(jié)果

4.1 網(wǎng)關(guān)項目啟動時

校驗結(jié)果正常:
SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密,web框架學(xué)習(xí),Java特性,spring cloud,gateway,spring boot,請求解密,響應(yīng)加密

4.2 發(fā)生請求時

可以看到data字段已經(jīng)加密響應(yīng)了。
SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密,web框架學(xué)習(xí),Java特性,spring cloud,gateway,spring boot,請求解密,響應(yīng)加密

請求和響應(yīng)結(jié)果:
SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密,web框架學(xué)習(xí),Java特性,spring cloud,gateway,spring boot,請求解密,響應(yīng)加密文章來源地址http://www.zghlxwxcb.cn/news/detail-739354.html

到了這里,關(guān)于SpringCloud Gateway實現(xiàn)請求解密和響應(yīng)加密的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 記一次線上bug排查-----SpringCloud Gateway組件 請求頭accept-encoding導(dǎo)致響應(yīng)結(jié)果亂碼

    記一次線上bug排查-----SpringCloud Gateway組件 請求頭accept-encoding導(dǎo)致響應(yīng)結(jié)果亂碼

    ? ? ? ?基于公司的業(yè)務(wù)需求,在SpringCloud Gateway組件的基礎(chǔ)上,寫了一個轉(zhuǎn)發(fā)服務(wù),測試開發(fā)階段運行正常,并實現(xiàn)初步使用。但三個月后,PostMan請求接口,返回異常,經(jīng)排查,從日志中獲取到轉(zhuǎn)發(fā)響應(yīng)的結(jié)果為亂碼: ? ? ?? 跟蹤日志: 轉(zhuǎn)發(fā)到目標接口,響應(yīng)結(jié)果已亂碼

    2024年02月04日
    瀏覽(23)
  • SpringCloud-Gateway實現(xiàn)RSA加解密

    SpringCloud-Gateway實現(xiàn)RSA加解密

    Gateway網(wǎng)關(guān)作為流量的入口,有的接口可能需要對請求內(nèi)容加密,返回結(jié)果加密,保證數(shù)據(jù)安全性。 一、RSA介紹 ????????RSA主要使用大整數(shù)分解這個數(shù)學(xué)難題進行設(shè)計,巧妙地利用了數(shù)論的概念。給了RSA公鑰,首先想到的攻擊就是分解模數(shù),給了的因子攻擊者可以計算得到

    2024年02月16日
    瀏覽(17)
  • spring boot如何實現(xiàn)對應(yīng)用系統(tǒng)進行請求加密、響應(yīng)加密處理

    參考文檔:https://blog.csdn.net/zhuocailing3390/article/details/125054315 通過實現(xiàn) RequestBodyAdvice 接口,對前端請求的參數(shù)進行解密并且重新讓真實結(jié)構(gòu)的數(shù)據(jù)進入到Controller中; 通過實現(xiàn) ResponseBodyAdvice 接口,將響應(yīng)的參數(shù)進行加密,返回到前端; 擴展: 可以通過自定義注解,實現(xiàn)對指

    2024年02月07日
    瀏覽(29)
  • 【SpringCloud Gateway】SpringCloud各微服務(wù)之間用戶登錄信息共享的實現(xiàn)思路——gateway網(wǎng)關(guān)token校驗以及向微服務(wù)發(fā)送請求攜帶token

    ? ? ? ? 最近在學(xué)習(xí)SpringCloud項目時,想到了一些問題,各個微服務(wù)分別部署在不同的服務(wù)上,由naocs作為注冊中心實現(xiàn)負載均衡,彼此之間通過Feign相互調(diào)用通信,信息同步并不像單體項目那樣方便,傳統(tǒng)單體項目的登錄驗證方式似乎在SpringCloud中不能滿足項目的需求。那么

    2024年02月05日
    瀏覽(20)
  • SpringCloud Gateway 3.x 響應(yīng)頭添加 Skywalking TraceId

    在微服務(wù)架構(gòu)中,一次請求可能會被多個服務(wù)處理,而每個服務(wù)又會產(chǎn)生相應(yīng)的日志,且每個服務(wù)也會有多個實例。在這種情況下,如果系統(tǒng)發(fā)生異常,沒有 Trace ID,那么在進行日志分析和追蹤時就會非常困難,因為我們無法將所有相關(guān)的日志信息串聯(lián)起來。 如果將 Trace I

    2023年04月24日
    瀏覽(28)
  • springcloud gateway中打印請求參數(shù),請求路徑和返回數(shù)據(jù)

    springcloud gateway中打印請求參數(shù),請求路徑和返回數(shù)據(jù)

    在平時前后端聯(lián)調(diào)過程中,需要查詢?nèi)罩究吹角岸苏埱蟮慕涌冢纤偷膮?shù),返回數(shù)據(jù)這樣有利于我們定位問題;話不多說直接上代碼。 在gateway模塊中,新建一個filter的包,然后創(chuàng)建改類,即可在控制臺和日志文件里面打印出請求參數(shù),只寫了常用的 post 和 get 請求的方式;

    2024年02月15日
    瀏覽(24)
  • Gateway全局異常處理及請求響應(yīng)監(jiān)控

    Gateway全局異常處理及請求響應(yīng)監(jiān)控

    我們在上一篇文章基于壓測進行Feign調(diào)優(yōu)完成的服務(wù)間調(diào)用的性能調(diào)優(yōu),此時我們也關(guān)注到一個問題,如果我們統(tǒng)一從網(wǎng)關(guān)調(diào)用服務(wù),但是網(wǎng)關(guān)因為某些原因報錯或者沒有找到服務(wù)怎么辦呢? 如下所示,筆者通過網(wǎng)關(guān)調(diào)用 account 服務(wù),但是 account 服務(wù)還沒起來。此時請求還沒

    2024年02月04日
    瀏覽(24)
  • SpringCloud微服務(wù)實戰(zhàn)——搭建企業(yè)級開發(fā)框架:微服務(wù)安全加固—自定義Gateway攔截器實現(xiàn)防止SQL注入/XSS攻擊

    ?SQL注入是常見的系統(tǒng)安全問題之一,用戶通過特定方式向系統(tǒng)發(fā)送SQL腳本,可直接自定義操作系統(tǒng)數(shù)據(jù)庫,如果系統(tǒng)沒有對SQL注入進行攔截,那么用戶甚至可以直接對數(shù)據(jù)庫進行增刪改查等操作。 ??XSS全稱為Cross Site Script跨站點腳本攻擊,和SQL注入類似,都是通過特定方

    2024年02月03日
    瀏覽(25)
  • 前端請求參數(shù)加密、.NET 后端解密

    前端請求參數(shù)加密、.NET 后端解密

    本文詳細介紹了前端請求參數(shù)加密、.NET 后端解密,文章較長,請各位看官耐心看完。 目錄 一、前端使用“CryptoJS”,前端AES加密,.NET后端AES解密 1.1、加密解密效果圖 1.2、CryptoJS介紹 1.3、準備工作:安裝“CryptoJS” 1.3.1、使用npm進行安裝 1.3.2、Visual Studio中安裝 1.3.2.1、選擇

    2024年02月08日
    瀏覽(29)
  • springcloud的gateway之GlobalFilter獲取請求信息及requestBody

    《本文參考地址》 RequestGlobalFilter.java ResponseGlobalFilter.java RequestAndResponseGlobalFilter.java

    2024年02月16日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包