在SpringCloud微服务框架下,可以通过网关gateway来进行统一的接口请求拦截,这里我主要用来做接口数据的加解密传输,这里使用了RSA非对称加密算法。(后面会附上完整代码)
首先先定义一个FilterConfig,实现GlobalFilter和Ordered两个接口

主要是实现filter拦截方法
 
 
rsaFilter函数的实现:
 整个拦截过程做了两件事:1、解密get请求参数,也就是url中的参数,2、解密body体中的请求参数,也就是post请求参数,这里前后端约定好了使用json传输。
 注:这里不会直接修改请求,而创建了一个新的请求然后分发下去,如果有多个filter也是一样。
 最终效果:
 如果是get请求,后端收到的格式统一为:https://xxx?param=xxxxxxx
 如果是post请求,后端收到的请求体格式统一为:{param: "xxxxxxx"}
GatewayFilterConfig:
import com.alibaba.fastjson.JSONObject;
import com.huaihai.common.utils.RSA.*;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.lang.reflect.Field;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.stream.Collectors;
/**
 * @author yeguodong
 * @date 2022/3/28
 */
@Configuration
@Component
public class GatewayFilterConfig implements GlobalFilter, Ordered {
    private static final String LOGIN_PATH = "/User/login";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
        // 验证token,如果是登录或者非后台不校验Token
//        String requestUrl = exchange.getRequest().getPath().value();
//        String userType = exchange.getRequest().getHeaders().getFirst(UserConstant.USER_TYPE);
//        AntPathMatcher pathMatcher = new AntPathMatcher();
//        if (!pathMatcher.match(LOGIN_PATH, requestUrl) && "admin".equalsIgnoreCase(userType)) {
//            String token = exchange.getRequest().getHeaders().getFirst(UserConstant.TOKEN);
//            Claims claim = TokenUtils.getClaim(token);
//            if (StringUtils.isBlank(token) || claim == null) {
//                return FilterUtils.invalidToken(exchange);
//            }
//        }
        return rsaFilter(exchange, chain);
        // 测试用,不拦截
//        return chain.filter(exchange);
    }
    /**
     * 拦截请求,rsa解密参数
     * @param exchange
     * @param chain
     * @return
     */
    private Mono rsaFilter(ServerWebExchange exchange, GatewayFilterChain chain) {
        MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
        if(!(MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)
                || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType))) {
            return chain.filter(exchange);
        }
        try {
            updateRequestParam(exchange);
        } catch (Exception e) {
            e.printStackTrace();
            return FilterUtils.invalidUrl(exchange);
        }
        ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
        Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
                .flatMap(body -> {
                    JSONObject jsonObject = JSONObject.parseObject(body);
                    String param = "";
                    try {
                        param = RSAUtils.decrypt(jsonObject.getString("param"), RSAConstant.PRIVATE_KEY);
                    } catch (Exception e) {
                    }
                    return Mono.just(param);
                });
        BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());
        headers.remove(HttpHeaders.CONTENT_LENGTH);
        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
        return bodyInserter.insert(outputMessage,  new BodyInserterContext())
                .then(Mono.defer(() -> {
                    ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
                            exchange.getRequest()) {
                        @Override
                        public HttpHeaders getHeaders() {
                            long contentLength = headers.getContentLength();
                            HttpHeaders httpHeaders = new HttpHeaders();
                            httpHeaders.putAll(super.getHeaders());
                            if (contentLength > 0) {
                                httpHeaders.setContentLength(contentLength);
                            } else {
                                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                            }
                            return httpHeaders;
                        }
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return outputMessage.getBody();
                        }
                    };
                    return chain.filter(exchange.mutate().request(decorator).build());
                }));
    }
    /**
     * 修改前端传的Get参数
     */
    private void updateRequestParam(ServerWebExchange exchange)
            throws NoSuchFieldException, IllegalAccessException, NoSuchPaddingException, NoSuchAlgorithmException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException {
        ServerHttpRequest request = exchange.getRequest();
        URI uri = request.getURI();
        String query = uri.getQuery();
        String[] split;
        if (StringUtils.isNotBlank(query)
                && query.contains("param")
                && (split = query.split("=")).length > 0) {
            String param = RSAUtils.decrypt(split[1], RSAConstant.PRIVATE_KEY);
            Field targetQuery = uri.getClass().getDeclaredField("query");
            targetQuery.setAccessible(true);
            targetQuery.set(uri, getParams(param));
        }
    }
    private String getParams(String query) {
        JSONObject jsonObject = JSONObject.parseObject(query);
        return jsonObject.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(Collectors.joining("&"));
    }
    @Override
    public int getOrder() {
        return Integer.MIN_VALUE;
    }
}
GatewayContext:
import org.springframework.util.MultiValueMap;
/**
 * @author yeguodong
 * @date 2022/4/6
 */
public class GatewayContext {
    public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";
    /**
     * cache json body
     */
    private String cacheBody;
    /**
     * cache formdata
     */
    private MultiValueMap<String, String> formData;
    /**
     * cache reqeust path
     */
    private String path;
    public String getCacheBody() {
        return cacheBody;
    }
    public void setCacheBody(String cacheBody) {
        this.cacheBody = cacheBody;
    }
    public MultiValueMap<String, String> getFormData() {
        return formData;
    }
    public void setFormData(MultiValueMap<String, String> formData) {
        this.formData = formData;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
}
RSAUtils:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
/**
 * @author yeguodong
 * @date 2022/3/31
 */
public class RSAUtils {
    public static final String PUBLIC_KEY = "public_key";
    public static final String PRIVATE_KEY = "private_key";
    public static String encrypt(String str, String publicKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
    }
    public static String decrypt(String str, String privateKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return new String(cipher.doFinal(inputByte));
    }
    private static Map<String, String> generateRasKey() {
        Map<String, String> rs = new HashMap<>();
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = null;
            keyPairGen = KeyPairGenerator.getInstance("RSA");
            keyPairGen.initialize(1024, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥 公钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
            // 将公钥和私钥保存到Map
            rs.put(PUBLIC_KEY, publicKeyString);
            rs.put(PRIVATE_KEY, privateKeyString);
        } catch (Exception e) {
        }
        return rs;
    }
    public static void main(String[] args) {
        System.out.println(generateRasKey());
    }
}
FilterUtils:
import com.alibaba.fastjson.JSONObject;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
 * @author yeguodong
 * @date 2022/4/1
 */
public class FilterUtils {
    private FilterUtils() {
    }
    public static Mono<Void> invalidToken(ServerWebExchange exchange) {
        JSONObject json = new JSONObject();
        json.put("code", HttpStatus.UNAUTHORIZED.value());
        json.put("msg", "无效的token");
        return buildReturnMono(json, exchange);
    }
    public static Mono<Void> invalidUrl(ServerWebExchange exchange){
        JSONObject json = new JSONObject();
        json.put("code", HttpStatus.BAD_REQUEST.value());
        json.put("msg", "无效的请求");
        return buildReturnMono(json, exchange);
    }
    public static Mono<Void> buildReturnMono(JSONObject json, ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        byte[] bits = json.toJSONString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码,否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
}

相关文章
暂无评论...
