当前位置: 代码网 > it编程>编程语言>Java > spring gateway & 响应加密

spring gateway & 响应加密

2024年08月02日 Java 我要评论
一般情况是,Filter Order 的问题。因为你这个Filter执行的优先级比较低导致被截断。不生效,请看这里,比较详细。

1、材料

jdk 1.8 + springboot  2.7.13 + springcloud 2021.0.8 + fastjson2.0 + hutool

pom:

 <groupid>org.springframework.cloud</groupid>
    <artifactid>spring-cloud-gateway</artifactid>
    <version>3.1.8</version>

2、编写filter:


import cn.hutool.core.collection.collutil;
import com.alibaba.fastjson2.json;
import lombok.extern.slf4j.slf4j;
import org.reactivestreams.publisher;
import org.springframework.boot.autoconfigure.condition.conditionalonproperty;
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.httpstatus;
import org.springframework.http.mediatype;
import org.springframework.http.server.pathcontainer;
import org.springframework.http.server.reactive.serverhttprequest;
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 org.springframework.web.util.pattern.pathpatternparser;
import reactor.core.publisher.flux;
import reactor.core.publisher.mono;

import javax.annotation.resource;
import java.net.uri;
import java.nio.charset.standardcharsets;
import java.util.list;
import java.util.map;
import java.util.objects;

/**
 * 定制密码过滤器
 * <p>
 * 1、请求解密
 * 2、响应加密
 * <p>
 * 目前优先做 2

 */
@component
// 触发配置
// @conditionalonproperty(value = "security.responseencrypt", havingvalue = "true")
@slf4j
public class responseencryptfilter implements globalfilter, ordered {

    @override
    public mono<void> filter(serverwebexchange exchange, gatewayfilterchain chain) {
        // 获取请求体
        serverhttprequest request = exchange.getrequest();
        mediatype mediatype = exchange.getrequest().getheaders().getcontenttype();
        // 判定是否为json请求
        if (mediatype != null
                && mediatype.includes(mediatype.application_json) ) {
            // 根据具体业务内容,修改响应体
            return modifyresponsebody(exchange, chain);
        }
        return chain.filter(exchange);
    }


    @override
    public int getorder() {
        // 参看这个类 org.springframework.core.ordered; 值越小,优先级越高
        return -200;
    }

    /**
     * 修改响应体
     *
     * @param exchange
     * @param chain
     * @return
     */
    private mono<void> modifyresponsebody(serverwebexchange exchange, gatewayfilterchain chain) {
        serverhttpresponse originalresponse = exchange.getresponse();
        originalresponse.getheaders().setcontenttype(mediatype.application_json);
        databufferfactory bufferfactory = originalresponse.bufferfactory();
        serverhttpresponsedecorator response = buildresponse(originalresponse, bufferfactory);
        return chain.filter(exchange.mutate().response(response).build());
    }

    private serverhttpresponsedecorator buildresponse(serverhttpresponse originalresponse, databufferfactory bufferfactory) {
        return new serverhttpresponsedecorator(originalresponse) {
            @override
            public mono<void> writewith(publisher<? extends databuffer> body) {
                if (getstatuscode().equals(httpstatus.ok) && body instanceof flux) {
                    flux<? extends databuffer> fluxbody = flux.from(body);
                    return super.writewith(fluxbody.buffer().map(databuffers -> {
                        databufferfactory databufferfactory = new defaultdatabufferfactory();
                        databuffer join = databufferfactory.join(databuffers);
                        byte[] content = new byte[join.readablebytecount()];
                        join.read(content);
                        databufferutils.release(join);
                        // 流转为字符串
                        string responsedata = new string(content, standardcharsets.utf_8);
                        //加密数据
                        responsedata = encryptresponse(responsedata);
                        byte[] uppedcontent = responsedata.getbytes(standardcharsets.utf_8);
                        originalresponse.getheaders().setcontentlength(uppedcontent.length);
                        return bufferfactory.wrap(uppedcontent);
                    }));
                } else {
                    log.error("获取响应体数据 :" + getstatuscode());
                }
                return super.writewith(body);
            }
            @override
            public mono<void> writeandflushwith(publisher<? extends publisher<? extends databuffer>> body) {
                return writewith(flux.from(body).flatmapsequential(p -> p));
            }
        };
    }

    private string encryptresponse(string originalresponsebody) {
        if (!secureproperties.enableencryptresponseparam()) {
            log.info("响应结果加密,跳过");
            return originalresponsebody;
        }
        map map = json.parseobject(originalresponsebody);
        //处理返回的数据
        object data = map.get("data");
        if (data != null) { 
           // 加密
            map.put("data",xxxx.encrypt(data.tostring()));
        }      
        return  json.tojsonstring(map);
    }
}

3、加密算法

完整代码仓库:springcloud-gateway-feng-demo: 使用网关做请求和响应的加解密

springcloud gateway实现请求解密和响应加密_springcloudgateway filter进行请求跟返回参数加解密-csdn博客

4、不生效问题

一般情况是,filter order 的问题。 因为你这个filter执行的优先级比较低导致被截断

请看这里,比较详细

【spring cloud gateway】serverhttpresponsedecorator不生效-csdn博客

5、url匹配

比如我们只想对某些uri进行处理,处理方式如下:

// 调用
 // 获取请求体
serverhttprequest request = exchange.getrequest();

isneedencrypt(request.geturi())


 private boolean isneedencrypt(uri uri) {
        list<string> encrypturilist = "你配置的待加密的uri列表";
        log.info("encrypturilist:{}",encrypturilist);
        if(collutil.isempty(encrypturilist)){
            return false;
        }
        string path = uri.getpath();
        for (string pathpattern : encrypturilist) {
            if (ismatch(path, pathpattern)) {
                return true;
            }
        }
        return false;
    }

    private boolean ismatch(string path, string pathpattern) {
        // 这里需要根据whitelisted的格式来判断和匹配
        // 对于简单ip可以直接比较,对于范围和cidr需要额外逻辑
        // ...
       return pathpatternparser.defaultinstance.parse(pathpattern).matches(pathcontainer.parsepath(path));
    }

6、小结

gateway处理加解密,比在其他地方处理更合理,当然,也可以通过requestbodyadvice 和 responsebodyadvice进行加解密。还有aop的方式 等等

springboot 基于requestbodyadvice 和 responsebodyadvice 实现数据的加/解密(采用 rsa 算法 ),“船新版本”!_wx64649997c45fd的技术博客_51cto博客

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com