在一些对安全要求很高的系统,需要对数据进行加密传输,我们可以采用在网关加密解密数据传输提高系统安全性,加密解密算法使用rsa(相对性能影响较小),java代码如下
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.google.common.base.Joiner;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.context.config.annotation.RefreshScope;
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.NettyDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
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.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;
/**
* @ClassName AppFilter
* @Description TODO
* @Author ljq
* @Date 2022/12/13 16:16
* @Version 1.0
*/
@Slf4j
@RefreshScope
@Component
public class AppFilter implements GlobalFilter, Ordered {
private static Joiner joiner = Joiner.on("");
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//如果存在appId 走应用认证接口
ServerHttpRequest request = exchange.getRequest();
String appId = request.getHeaders().getFirst("appId");
if(StringUtils.isNotBlank(appId)){
if (exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
String bodyStr = getBodyStr(exchange.getRequest().getBody());
log.info("加密原始数据"+bodyStr);
//重新封装请求 因为请求体内容已被消费,需要重新写入
URI uri = request.getURI();
request = request.mutate().uri(uri).build();
//这块需要掉用微服务进行应用权限校验 并返回应用公私钥 这里使用hutu工具包 对数据进行rsa加解密 start
String privateKey = "30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100b9c7d70130df32ff4f41f79390fc085439e917a632b2707c0d3d4c8da0cedc22e55d66ddbe59287b16aa63ff3a98d23e3938da0ceabac4167204e09a3a0cd88f020301000102401f5ae821ce52cd73a3b7d98631612832b6f76d4362a9152d0abafed1a4836549c042700fc26b750a460c999c9a0107aec4cdfecde897606dcc56bb653aee1a89022100f773cf5f947e4eb442b8a2ba42929a557e2b6c48869347296fe6e5a5c7e12513022100c032ac9e7c2ca7ca817bdd8626fe25f427188c10bc42206fd3605764f767ba15022100f0653ded29219bec5b756c016f736523f132d63b8f21bd5c702deca4258e80a9022043e3625fd4c2bd3de580c81db3b63fd7bedb87d5fd796a15b5d728e78c104285022100879796fca38aadf54a0dd90959d1eef452fffe504d73dbaff887f5089e36cd19";
String publicKey = "305c300d06092a864886f70d0101010500034b003048024100b9c7d70130df32ff4f41f79390fc085439e917a632b2707c0d3d4c8da0cedc22e55d66ddbe59287b16aa63ff3a98d23e3938da0ceabac4167204e09a3a0cd88f0203010001";
RSA rsa = SecureUtil.rsa(privateKey,publicKey);
bodyStr = rsa.decryptStr(bodyStr, KeyType.PrivateKey);
log.info("解密数据:"+bodyStr);
//这块需要掉用微服务进行应用权限校验 并返回应用公私钥 这里使用hutu工具包 对数据进行rsa加解密 end
//将解密数据封装向下传递
DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
Flux bodyFlux = Flux.just(bodyDataBuffer);
request = new ServerHttpRequestDecorator(request) {
@Override
public Flux getBody() {
return bodyFlux;
}
};
//可以选择对返回体也进行加密
ResBodyEncryptDecorator responseDecorator = new ResBodyEncryptDecorator(exchange.getResponse(),exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR),rsa);
ServerHttpRequest newRequest = request.mutate().build();
return chain.filter(exchange.mutate().request(newRequest).response(responseDecorator).build());
}else{
//可以将get请求也设置特定的参数读取加解密 可以照着post请求做
return AppIdInvalid(exchange);
}
}else{
return AppIdInvalid(exchange);
}
}
public static class ResBodyEncryptDecorator extends ServerHttpResponseDecorator{
private DataBufferFactory bufferFactory;
private String contentType;
private RSA rsa;
public ResBodyEncryptDecorator(ServerHttpResponse delegate,String contentType,RSA rsa) {
super(delegate);
this.contentType = contentType;
this.bufferFactory = delegate.bufferFactory();
this.rsa = rsa;
}
@Override
public Mono writeWith(Publisher<? extends DataBuffer> body) {
log.info("得到响应体");
if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
// 获取响应 ContentType
// 记录 JSON 格式数据的响应体
if (!StringUtils.isEmpty(contentType) && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
// 解决返回体分段传输
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
List list = Lists.newArrayList();
dataBuffers.forEach(dataBuffer -> {
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
list.add(new String(content, Charset.forName("UTF-8")));
});
String responseData = joiner.join(list);
log.info("得到响应体内容:{}", responseData.replaceAll("
","").replaceAll(" ",""));
responseData = rsa.encryptBase64(responseData, KeyType.PublicKey);
return bufferFactory.wrap(responseData.getBytes());
}));
}
}
return super.writeWith(body);
}
}
/**
* token 无效,消息返回
* @param exchange
* @return
*/
private Mono AppIdInvalid(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
byte[] bits = "{"result":"-1","message":"应用不存在","data":null}".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));
}
/**
* 获取请求体内容
* @param body
* @return
*/
private String getBodyStr(Flux body) {
AtomicReference bodyRef = new AtomicReference<>();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
log.info(charBuffer.toString());
});
//获取request body
return bodyRef.get();
}
private DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
public static void main(String[] args) {
String privateKey = "30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100b9c7d70130df32ff4f41f79390fc085439e917a632b2707c0d3d4c8da0cedc22e55d66ddbe59287b16aa63ff3a98d23e3938da0ceabac4167204e09a3a0cd88f020301000102401f5ae821ce52cd73a3b7d98631612832b6f76d4362a9152d0abafed1a4836549c042700fc26b750a460c999c9a0107aec4cdfecde897606dcc56bb653aee1a89022100f773cf5f947e4eb442b8a2ba42929a557e2b6c48869347296fe6e5a5c7e12513022100c032ac9e7c2ca7ca817bdd8626fe25f427188c10bc42206fd3605764f767ba15022100f0653ded29219bec5b756c016f736523f132d63b8f21bd5c702deca4258e80a9022043e3625fd4c2bd3de580c81db3b63fd7bedb87d5fd796a15b5d728e78c104285022100879796fca38aadf54a0dd90959d1eef452fffe504d73dbaff887f5089e36cd19";
String publicKey = "305c300d06092a864886f70d0101010500034b003048024100b9c7d70130df32ff4f41f79390fc085439e917a632b2707c0d3d4c8da0cedc22e55d66ddbe59287b16aa63ff3a98d23e3938da0ceabac4167204e09a3a0cd88f0203010001";
RSA rsa = SecureUtil.rsa(privateKey,publicKey);
String data = "{
" +
" "current":1,
" +
" "size":20,
" +
" "param":{
" +
" "afterSale":"Y",
" +
" "commitTimeStart":"2011-11-11 00:00:00"
" +
" }
" +
"}";
String encrypt = rsa.encryptBase64(data, KeyType.PrivateKey);
String decypt = rsa.decryptStr(encrypt, KeyType.PublicKey);
System.out.println(encrypt);
System.out.println(decypt);
encrypt = rsa.encryptBase64(data, KeyType.PublicKey);
decypt = rsa.decryptStr(encrypt, KeyType.PrivateKey);
System.out.println(encrypt);
System.out.println(decypt);
}
@Override
public int getOrder() {
return -2;
}
}
遇到的问题:
1 有可能无法获取到请求体里面的内容可以参考 https://zhuanlan.zhihu.com/p/471402045
效果:
页面更新:2024-03-01
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号