gateway拦截数据加解密
gateway网关加解密
分布式gateway 信息统一拦截加密(复制直接用)
1.和前端协商好加密算法,小编这里用的是AES代码如下
public class AesEncryptUtil {
//使用AES-128-CBC加密模式,key需要为16位,key和iv可以相同!
private static final String KEY = ConstantFilter.S_KEY;
private static final String IV = ConstantFilter.IV_PARAMETER;
/**
* 加密方法
*
* @param data 要加密的数据
* @param key 加密key
* @param iv 加密iv
* @return 加密的结果
* @throws Exception
*/
public static String encrypt(String data, String key, String iv) throws Exception {
try {
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);//"算法/模式/补码方式"NoPadding PkcsPadding
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
if(plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), “AES”);
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return new Base64().encodeToString(encrypted);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 解密方法
*
* @param data 要解密的数据
* @param key 解密key
* @param iv 解密iv
* @return 解密的结果
* @throws Exception
*/
public static String desEncrypt(String data, String key, String iv) throws Exception {
try {
byte[] encrypted1 = new Base64().decode(data);
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), “AES”);
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用默认的key和iv加密
*
* @param data
* @return
* @throws Exception
*/
public static String encrypt(String data) throws Exception {
return encrypt(data, KEY, IV);
}
/**
* 使用默认的key和iv解密
*
* @param data
* @return
* @throws Exception
*/
public static String desEncrypt(String data) throws Exception {
return desEncrypt(data, KEY, IV);
}
}
2.对所有返回数据进行加密,具体逻辑是这样的:
(一)获取前端传入的请求头,根据请求头内的值日判断接口是否加密
(二)对数据加密,并且释放掉内存否则会内存溢出
(三)正常返回数据
(四)直接贴代码
public class ResFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
//获取前端传入的请求头,如果授权即默认为加密处理
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY);
if(ConstantFilter.REQ_RES_ENCRYPT.equals(token)) {
log.info(“返回数据加密状态为【加密】,当前时间:” + new Date());
long lStart = System.currentTimeMillis();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono writeWith(Publisher<? extends DataBuffer> body) {
if(body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) 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 str = new String(content, Charset.forName("UTF-8"));
log.info("返回的源数据》》小程序:" + str);
log.info("返回的源数据》》小程序:" + str);
// 把下面加密方法改成你自己的
// String encryptStr = Base64.getEncoder().encodeToString(Encodes.encryptAES1(str));
String encryptStr = null;
try {
encryptStr = AesEncryptUtil.encrypt(str);
}
catch(Exception e) {
e.printStackTrace();
}
log.info("返回的加密数据秘钥为:" + "[" + encryptStr + "]");
log.info("返回的加密数据秘钥为:" + "[" + encryptStr + "]");
originalResponse.getHeaders().setContentLength(encryptStr.getBytes().length);
return bufferFactory.wrap(encryptStr.getBytes());
}));
}
return super.writeWith(body);
}
};
// 将响应替换为装饰器
long lUseTime = System.currentTimeMillis() - lStart;
log.info("返回加密逻辑耗时为:" + lUseTime + ",毫秒");
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
// else if(ConstantFilter.REQ_RES_NALMORE.equals(token)) {
else {
long lStart = System.currentTimeMillis();
log.info("返回数据加密状态为【不加密】,当前时间:" + new Date());
ServerHttpResponseDecorator decoratedResponse1 = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if(body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) 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 str = new String(content, Charset.forName("UTF-8"));
log.info(str);
// 把下面加密方法改成你自己的
String encryptStr = str;
originalResponse.getHeaders().setContentLength(encryptStr.getBytes().length);
return bufferFactory.wrap(encryptStr.getBytes());
}));
}
return super.writeWith(body);
}
};
//将响应替换为装饰器
long lUseTime = System.currentTimeMillis() - lStart;
log.info("返回参数不加密逻辑耗时为:" + lUseTime + ",毫秒");
return chain.filter(exchange.mutate().response(decoratedResponse1).build());
}
// return null;
}
@Override
public int getOrder() {
return -1;
}
3.对请求数据进行拦截解密,具体逻辑如下:
(一)重新构造request,参考ModifyRequestBodyGatewayFilterFactory
(二)因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
具体代如下:
@Component
@Slf4j
public class ReqFilter implements GlobalFilter, Ordered {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers,
CachedBodyOutputMessage outputMessage)
{
return new ServerHttpRequestDecorator(exchange.getRequest()) {
public HttpHeaders getHeaders() {
long contentLength = headers.getContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
if(contentLength > 0L) {
httpHeaders.setContentLength(contentLength);
}
else {
httpHeaders.set(“Transfer-Encoding”, “chunked”);
}
return httpHeaders;
}
public Flux<DataBuffer> getBody() {
return outputMessage.getBody();
}
};
}
private Mono returnMononew(GatewayFilterChain chain, ServerWebExchange exchange) {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
}));
}
private Mono readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
//重新构造request,参考ModifyRequestBodyGatewayFilterFactory
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
//重点
Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
//因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
if(MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) ||
MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType))
{
String newBody = null;
try {
log.info(“小程序》》前端源数据为:” + body);
log.info(“小程序》》前端源数据为:” + body);
// 解密body 此处调用你自己的解密方法
newBody = AesEncryptUtil.desEncrypt(body);
log.info(“前端解密后的数据为:” + “[” + newBody + “]”);
log.info(“前端解密后的数据为:” + “[” + newBody + “]”);
}
catch(Exception e) {
e.getMessage();
}
return Mono.just(newBody);
}
return Mono.empty();
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
//猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
headers.remove(“Content-Length”);
//MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
return returnMononew(chain, exchange.mutate().request(decorator).build());
}));
}
private Mono notDecrypt(ServerWebExchange exchange, GatewayFilterChain chain) {
//重新构造request,参考ModifyRequestBodyGatewayFilterFactory
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
MediaType mediaType = exchange.getRequest().getHeaders().getContentType();
//重点
Mono modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> {
//因为约定了终端传参的格式,所以只考虑json的情况,如果是表单传参,请自行增加
if(MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) ||
MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType))
{
String newBody = null;
try {
// 解密body 此处调用你自己的解密方法
newBody = body;
}
catch(Exception e) {
e.getMessage();
}
return Mono.just(newBody);
}
return Mono.empty();
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
//猜测这个就是之前报400错误的元凶,之前修改了body但是没有重新写content length
headers.remove(“Content-Length”);
//MyCachedBodyOutputMessage 这个类完全就是CachedBodyOutputMessage,只不过CachedBodyOutputMessage不是公共的
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage);
return returnMononew(chain, exchange.mutate().request(decorator).build());
}));
}
@SneakyThrows
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
String path = request.getURI().getPath(); // 当前调用方法的url
HttpHeaders headers = request.getHeaders();
log.info("HttpMethod:{},Url:{}", request.getMethod(), request.getURI().getRawPath());
// 登录跳过网关验证,检查白名单(配置)最好把不拦截路径放入配置文件,此处通过正则
if(antPathMatcher.match("/**/api/login/auth/**", path)) {
return readBody(exchange, chain);
}
// 处理参数
MediaType contentType = headers.getContentType();
long contentLength = headers.getContentLength();
ServerHttpRequest request1 = exchange.getRequest();
//目前支持POST
if(contentLength > 0) {
long lStart = System.currentTimeMillis();
if(MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
if(ConstantFilter.REQ_RES_ENCRYPT.equals(request1.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY))) {
log.info("入参加密状态为【解密】,当前时间:" + new Date());
return readBody(exchange, chain);
}
// else if(ConstantFilter.REQ_RES_NALMORE.equals(
// request1.getHeaders().getFirst(ConstantFilter.BG_DEBUG_KEY)))
// {
else {
log.info("入参加密状态为【不解密】,当前时间:" + new Date());
return notDecrypt(exchange, chain);
}
}
long lUseTime = System.currentTimeMillis() - lStart;
log.info("入参加密逻辑耗时:" + lUseTime + ",毫秒");
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
更多推荐
所有评论(0)