Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
ee8587d014
|
|
@ -17,10 +17,7 @@ import io.jsonwebtoken.Claims;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
@ -56,7 +53,6 @@ public class TokenController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地推出登录
|
* 本地推出登录
|
||||||
* @param request
|
* @param request
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,14 @@ spring:
|
||||||
server-addr: 127.0.0.1:8848
|
server-addr: 127.0.0.1:8848
|
||||||
# server-addr: 27.196.164.56:8848
|
# server-addr: 27.196.164.56:8848
|
||||||
namespace: jjzhgd
|
namespace: jjzhgd
|
||||||
|
username: nacos
|
||||||
|
password: Jjsp@nacos2023
|
||||||
config:
|
config:
|
||||||
# server-addr: 27.196.164.56:8848
|
# server-addr: 27.196.164.56:8848
|
||||||
server-addr: 127.0.0.1:8848
|
server-addr: 127.0.0.1:8848
|
||||||
namespace: jjzhgd
|
namespace: jjzhgd
|
||||||
|
username: nacos
|
||||||
|
password: Jjsp@nacos2023
|
||||||
# 配置文件格式
|
# 配置文件格式
|
||||||
file-extension: yml
|
file-extension: yml
|
||||||
# 共享配置
|
# 共享配置
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.securitycontrol.common.core.utils;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: meng
|
||||||
|
* @Description: 常用变量
|
||||||
|
* @Date: 2023/3/30 10:29
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CommonConstant {
|
||||||
|
|
||||||
|
//JWT密钥
|
||||||
|
public static final String JWT_TOKEN = "jwt-token";
|
||||||
|
|
||||||
|
//请求头中的token
|
||||||
|
public static final String X_TOKEN = "X-TOKEN";
|
||||||
|
|
||||||
|
//请求头中的sign
|
||||||
|
public static final String X_SIGN = "X-SIGN";
|
||||||
|
|
||||||
|
public static final String X_APPID = "X-APPID";
|
||||||
|
|
||||||
|
public static final String CODE = "code";
|
||||||
|
|
||||||
|
public static final String MESSAGE = "message";
|
||||||
|
|
||||||
|
public static final String UTF8 = "UTF-8";
|
||||||
|
|
||||||
|
public static final String RSA_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFJIl4il6nDBlF/3byWB/KXRqfEXkviz7ZvO7TU7JBfh7sFqfgLtJFDSA33+qTHOtYTCjCrwl6oWWX7Aff39HiFW1IBnhKjYdSK5/8ruQY+Y2xbpBMgslA0m2euOv3XPJUXWh0JGBqPllgzvtbtUA1iBELAHVYBACuQPYP2VcPeQIDAQAB";
|
||||||
|
public static final String RSA_PRIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMUkiXiKXqcMGUX/dvJYH8pdGp8ReS+LPtm87tNTskF+HuwWp+Au0kUNIDff6pMc61hMKMKvCXqhZZfsB9/f0eIVbUgGeEqNh1Irn/yu5Bj5jbFukEyCyUDSbZ646/dc8lRdaHQkYGo+WWDO+1u1QDWIEQsAdVgEAK5A9g/ZVw95AgMBAAECgYABvRrBR2ciTgcDCQfBh2lwXXXYpUzOUIoTXYk1r+1IipY3OtPsND2CgmUgWQc2mPCybKmHXgfVXwsIVfqTzOOK+PEMVGYNflUdXgV3hNffRzl/nfPdpqhb2ALu8ftPwiGq5QN2PqaRgY9kM67Ye/cCjFzm/kLIqsNuXLKiQc1ioQJBAO7g4ZBcG/D0IxtiR4RdXYtr4wQc+cmscSKj5RPNBwn0bh9psOSg2loS/wWUmCnYSncsLGgMzPl+yPkTLwGryH0CQQDTRduiOzu6bFdOw6tI6eOxHB5h0kfcim4VT/Huh5RyP+GC7kLBmknbBO/tQXxSDVaG81Pkr+INHxJmctfKik+tAkEAtBIrl0IIAhRXnp3wYXRsPtxeLkyVc5SdWEqKNen5Y2Sx2tY2dbJXx0zIl3FTXz/fqoRPGUSFA5Kydygh6DWRlQJBAMmOfOHB9tJ8Z7LJ85AFKucdt1KFpW8eVbVZZqq0iAeTMBaULfW7tzgO9sJ3Vh6FgQYP//pNXbA883XvnDUrTKUCQQDgLO7mThmy7iqqo0be4a2ycy9fvORFYzSq1t6mTd+gr73CMCy2bTmyv/Qp4QsuPIKea0iE+HA/la5zlM8eAxOq";
|
||||||
|
//公共返回方法
|
||||||
|
public static Mono<Void> buildResponse(ServerWebExchange exchange, int code, String message) {
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put(CODE, code);
|
||||||
|
jsonObject.put(MESSAGE, message);
|
||||||
|
DataBuffer bodyDataBuffer = response.bufferFactory().wrap(jsonObject.toJSONString().getBytes());
|
||||||
|
return response.writeWith(Mono.just(bodyDataBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ public class AesCbcUtils {
|
||||||
/**
|
/**
|
||||||
* AES要求密钥长度为128位或192位或256位,java默认限制AES密钥长度最多128位
|
* AES要求密钥长度为128位或192位或256位,java默认限制AES密钥长度最多128位
|
||||||
*/
|
*/
|
||||||
public static String sKey = "zhst@bonus@zhst@bonus@1234567890";
|
public static String sKey = "zhgd@bonus@zhgd@bonus@1234567890";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编码格式导出
|
* 编码格式导出
|
||||||
|
|
@ -58,26 +58,44 @@ public class AesCbcUtils {
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
* @return 加密后的密文
|
* @return 加密后的密文
|
||||||
*/
|
*/
|
||||||
public static String encrypt(String source, String key) throws Exception {
|
public static String encrypt(String source ) {
|
||||||
byte[] sourceBytes = source.getBytes(ENCODING);
|
try{
|
||||||
byte[] keyBytes = key.getBytes(ENCODING);
|
String key=sKey;
|
||||||
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
|
byte[] sourceBytes = source.getBytes(ENCODING);
|
||||||
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(ENCODING));
|
byte[] keyBytes = key.getBytes(ENCODING);
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM), iv);
|
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
|
||||||
byte[] decrypted = cipher.doFinal(sourceBytes);
|
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(ENCODING));
|
||||||
return Base64.encodeBase64String(decrypted);
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM), iv);
|
||||||
|
byte[] decrypted = cipher.doFinal(sourceBytes);
|
||||||
|
return Base64.encodeBase64String(decrypted);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.toString(),e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// String json="username=guest&password=admin@123";
|
||||||
|
|
||||||
|
String json="{\"username\":\"guest\",\"password\":\"admin@123\"}";
|
||||||
|
String data=encrypt(json);
|
||||||
|
System.err.println(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AES解密
|
* AES解密
|
||||||
*(CBC模式)
|
*(CBC模式)
|
||||||
* @param encryptStr 加密后的密文
|
* @param data 加密后的密文
|
||||||
* @param
|
* @param
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
* @return 源字符串
|
* @return 源字符串
|
||||||
*/
|
*/
|
||||||
public static String decrypt(String encryptStr) {
|
public static String decrypt(String data) {
|
||||||
try{
|
try{
|
||||||
|
String encryptStr="";
|
||||||
|
if(StringHelper.isNotEmpty(data)){
|
||||||
|
encryptStr=data.replace(" ","+");
|
||||||
|
}
|
||||||
String key=sKey;
|
String key=sKey;
|
||||||
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
|
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
|
||||||
byte[] keyBytes = key.getBytes(ENCODING);
|
byte[] keyBytes = key.getBytes(ENCODING);
|
||||||
|
|
@ -87,9 +105,10 @@ public class AesCbcUtils {
|
||||||
byte[] decoded = cipher.doFinal(sourceBytes);
|
byte[] decoded = cipher.doFinal(sourceBytes);
|
||||||
return new String(decoded, ENCODING);
|
return new String(decoded, ENCODING);
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
|
log.info("------------------->请求加密参数不正确");
|
||||||
log.error(e.toString(),e);
|
log.error(e.toString(),e);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.securitycontrol.common.core.utils.aes;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.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 黑子
|
||||||
|
*/
|
||||||
|
public final class MonoUtils {
|
||||||
|
|
||||||
|
private MonoUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public static Mono<Void> invalidUrl(ServerWebExchange exchange){
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("code", 400);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.securitycontrol.gateway.filter;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: meng
|
||||||
|
* @Description: 网关上下文
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GatewayContext {
|
||||||
|
|
||||||
|
public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cache headers
|
||||||
|
*/
|
||||||
|
private HttpHeaders headers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cache json body
|
||||||
|
*/
|
||||||
|
private String cacheBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cache formdata
|
||||||
|
*/
|
||||||
|
private MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipAddress
|
||||||
|
*/
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path
|
||||||
|
*/
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,236 @@
|
||||||
|
package com.securitycontrol.gateway.filter;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.codec.HttpMessageReader;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
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 java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: https://blog.csdn.net/zx156955/article/details/115004910
|
||||||
|
* @Description: 请求内容存储 处理请求内容 内容放在gatewayContext中
|
||||||
|
* @Date: 2023/3/30 10:11
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class RequestCoverFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default HttpMessageReader
|
||||||
|
*/
|
||||||
|
private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReadFormData
|
||||||
|
*
|
||||||
|
* @param exchange
|
||||||
|
* @param chain
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain,
|
||||||
|
GatewayContext gatewayContext) {
|
||||||
|
final ServerHttpRequest request = exchange.getRequest();
|
||||||
|
HttpHeaders headers = request.getHeaders();
|
||||||
|
|
||||||
|
return exchange.getFormData().doOnNext(multiValueMap -> {
|
||||||
|
gatewayContext.setFormData(multiValueMap);
|
||||||
|
log.debug("[GatewayContext]Read FormData:{}", multiValueMap);
|
||||||
|
}).then(Mono.defer(() -> {
|
||||||
|
Charset charset = headers.getContentType().getCharset();
|
||||||
|
charset = charset == null ? StandardCharsets.UTF_8 : charset;
|
||||||
|
String charsetName = charset.name();
|
||||||
|
MultiValueMap<String, String> formData = gatewayContext.getFormData();
|
||||||
|
/**
|
||||||
|
* formData is empty just return
|
||||||
|
*/
|
||||||
|
if (null == formData || formData.isEmpty()) {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
StringBuilder formDataBodyBuilder = new StringBuilder();
|
||||||
|
String entryKey;
|
||||||
|
List<String> entryValue;
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* repackage form data
|
||||||
|
*/
|
||||||
|
for (Map.Entry<String, List<String>> entry : formData.entrySet()) {
|
||||||
|
entryKey = entry.getKey();
|
||||||
|
entryValue = entry.getValue();
|
||||||
|
if (entryValue.size() > 1) {
|
||||||
|
for (String value : entryValue) {
|
||||||
|
formDataBodyBuilder.append(entryKey).append("=")
|
||||||
|
.append(URLEncoder.encode(value, charsetName)).append("&");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formDataBodyBuilder.append(entryKey).append("=")
|
||||||
|
.append(URLEncoder.encode(entryValue.get(0), charsetName)).append("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// ignore URLEncode Exception
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* substring with the last char '&'
|
||||||
|
*/
|
||||||
|
String formDataBodyString = "";
|
||||||
|
if (formDataBodyBuilder.length() > 0) {
|
||||||
|
formDataBodyString = formDataBodyBuilder.substring(0, formDataBodyBuilder.length() - 1);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* get data bytes
|
||||||
|
*/
|
||||||
|
byte[] bodyBytes = formDataBodyString.getBytes(charset);
|
||||||
|
int contentLength = bodyBytes.length;
|
||||||
|
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(request) {
|
||||||
|
/**
|
||||||
|
* change content-length
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public HttpHeaders getHeaders() {
|
||||||
|
HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
httpHeaders.putAll(super.getHeaders());
|
||||||
|
if (contentLength > 0) {
|
||||||
|
httpHeaders.setContentLength(contentLength);
|
||||||
|
} else {
|
||||||
|
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
||||||
|
}
|
||||||
|
return httpHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read bytes to Flux<Databuffer>
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody() {
|
||||||
|
return DataBufferUtils.read(new ByteArrayResource(bodyBytes),
|
||||||
|
new NettyDataBufferFactory(ByteBufAllocator.DEFAULT), contentLength);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ServerWebExchange mutateExchange = exchange.mutate().request(decorator).build();
|
||||||
|
log.info("[GatewayContext]Rewrite Form Data :{}", formDataBodyString);
|
||||||
|
|
||||||
|
return chain.filter(mutateExchange);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReadJsonBody
|
||||||
|
*
|
||||||
|
* @param exchange
|
||||||
|
* @param chain
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext) {
|
||||||
|
/**
|
||||||
|
* join the body
|
||||||
|
*/
|
||||||
|
return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
|
||||||
|
/*
|
||||||
|
* read the body Flux<DataBuffer>, and release the buffer
|
||||||
|
* see PR https://github.com/spring-cloud/spring-cloud-gateway/pull/1095
|
||||||
|
*/
|
||||||
|
byte[] bytes = new byte[dataBuffer.readableByteCount()];
|
||||||
|
dataBuffer.read(bytes);
|
||||||
|
DataBufferUtils.release(dataBuffer);
|
||||||
|
Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
|
||||||
|
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
|
||||||
|
DataBufferUtils.retain(buffer);
|
||||||
|
return Mono.just(buffer);
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* repackage ServerHttpRequest
|
||||||
|
*/
|
||||||
|
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody() {
|
||||||
|
return cachedFlux;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* mutate exchage with new ServerHttpRequest
|
||||||
|
*/
|
||||||
|
ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
|
||||||
|
/**
|
||||||
|
* read body string with default messageReaders
|
||||||
|
*/
|
||||||
|
return ServerRequest.create(mutatedExchange, messageReaders).bodyToMono(String.class)
|
||||||
|
.doOnNext(objectValue -> {
|
||||||
|
gatewayContext.setCacheBody(objectValue);
|
||||||
|
log.debug("[GatewayContext]Read JsonBody:{}", objectValue);
|
||||||
|
}).then(chain.filter(mutatedExchange));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return HIGHEST_PRECEDENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
/**
|
||||||
|
* save request path and serviceId into gateway context
|
||||||
|
*/
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
|
|
||||||
|
GatewayContext gatewayContext = new GatewayContext();
|
||||||
|
String path = request.getPath().pathWithinApplication().value();
|
||||||
|
gatewayContext.setPath(path);
|
||||||
|
gatewayContext.getFormData().addAll(request.getQueryParams());
|
||||||
|
gatewayContext.setIpAddress(String.valueOf(request.getRemoteAddress()));
|
||||||
|
HttpHeaders headers = request.getHeaders();
|
||||||
|
gatewayContext.setHeaders(headers);
|
||||||
|
log.debug("HttpMethod:{},Url:{}", request.getMethod(), request.getURI().getRawPath());
|
||||||
|
|
||||||
|
/// 注意,因为webflux的响应式编程 不能再采取原先的编码方式 即应该先将gatewayContext放入exchange中,否则其他地方可能取不到
|
||||||
|
/**
|
||||||
|
* save gateway context into exchange
|
||||||
|
*/
|
||||||
|
exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);
|
||||||
|
|
||||||
|
// 处理参数
|
||||||
|
MediaType contentType = headers.getContentType();
|
||||||
|
long contentLength = headers.getContentLength();
|
||||||
|
if (contentLength > 0) {
|
||||||
|
if (MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
|
||||||
|
return readBody(exchange, chain, gatewayContext);
|
||||||
|
}
|
||||||
|
if (MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) {
|
||||||
|
return readFormData(exchange, chain, gatewayContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("[GatewayContext]ContentType:{},Gateway context is set with {}", contentType, gatewayContext);
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
package com.securitycontrol.gateway.filter;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.CryptoException;
|
||||||
|
import com.securitycontrol.common.core.utils.CommonConstant;
|
||||||
|
import com.securitycontrol.common.core.utils.StringUtils;
|
||||||
|
import com.securitycontrol.common.core.utils.aes.AesCbcUtils;
|
||||||
|
import com.securitycontrol.common.core.utils.aes.MonoUtils;
|
||||||
|
import com.securitycontrol.common.core.utils.aes.StringHelper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: meng
|
||||||
|
* @Description: RSA实现对请求参数解密
|
||||||
|
* @Date: 2023/4/6 15:20
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
class RsaDecryptResponseGatewayFilterFactory extends AbstractGatewayFilterFactory {
|
||||||
|
|
||||||
|
@Value("${system.jm}")
|
||||||
|
public boolean AQ_JM;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GatewayFilter apply(Object config) {
|
||||||
|
return (exchange, chain) -> {
|
||||||
|
ServerHttpRequest serverHttpRequest = exchange.getRequest();
|
||||||
|
if(!AQ_JM){
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
//get请求 默认
|
||||||
|
if(HttpMethod.GET.matches(serverHttpRequest.getMethodValue())){//如果是get
|
||||||
|
if(exchange.getRequest().getQueryParams().isEmpty()){//如果参数是空的
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}else{
|
||||||
|
try{
|
||||||
|
updateRequestParam(exchange);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.toString(),e);
|
||||||
|
return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!HttpMethod.POST.matches(serverHttpRequest.getMethodValue())) {//非 post请求
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
byte[] decrypBytes;
|
||||||
|
GatewayContext gatewayContext = exchange.getAttribute(GatewayContext.CACHE_GATEWAY_CONTEXT);
|
||||||
|
if(StrUtil.isBlank(gatewayContext.getCacheBody())){
|
||||||
|
if(!exchange.getRequest().getQueryParams().isEmpty()){
|
||||||
|
try{
|
||||||
|
updateRequestParam(exchange);
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error(e.toString(),e);
|
||||||
|
return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//未强制加密
|
||||||
|
return chain.filter(exchange);
|
||||||
|
|
||||||
|
// return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "请求参数不能为空");
|
||||||
|
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 获取request body
|
||||||
|
String requestBody = gatewayContext.getCacheBody();
|
||||||
|
String decryptMsg= AesCbcUtils.decrypt(requestBody);
|
||||||
|
gatewayContext.setCacheBody(decryptMsg);
|
||||||
|
decrypBytes = decryptMsg.getBytes();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("数据 解密失败:{}", e);
|
||||||
|
return CommonConstant.buildResponse(exchange, HttpStatus.BAD_REQUEST.value(), "数据解密失败");
|
||||||
|
}
|
||||||
|
// 根据解密后的参数重新构建请求
|
||||||
|
DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
|
||||||
|
Flux<DataBuffer> bodyFlux = Flux.just(dataBufferFactory.wrap(decrypBytes));
|
||||||
|
ServerHttpRequest newRequest = serverHttpRequest.mutate().uri(serverHttpRequest.getURI()).build();
|
||||||
|
newRequest = new ServerHttpRequestDecorator(newRequest) {
|
||||||
|
@Override
|
||||||
|
public Flux<DataBuffer> getBody() {
|
||||||
|
return bodyFlux;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 构建新的请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.putAll(exchange.getRequest().getHeaders());
|
||||||
|
// 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
|
||||||
|
int length = decrypBytes.length;
|
||||||
|
headers.remove(HttpHeaders.CONTENT_LENGTH);
|
||||||
|
headers.setContentLength(length);
|
||||||
|
newRequest = new ServerHttpRequestDecorator(newRequest) {
|
||||||
|
@Override
|
||||||
|
public HttpHeaders getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 把解密后的数据重置到exchange自定义属性中,在之后的日志GlobalLogFilter从此处获取请求参数打印日志
|
||||||
|
exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);
|
||||||
|
return chain.filter(exchange.mutate().request(newRequest).build());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改前端传的参数
|
||||||
|
*/
|
||||||
|
private void updateRequestParam(ServerWebExchange exchange) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
URI uri = request.getURI();
|
||||||
|
//请求参数
|
||||||
|
String query = uri.getQuery();
|
||||||
|
//判断是否有加密的参数 这里的约定是 param
|
||||||
|
if (StringUtils.isNotBlank(query) && query.contains("params")) {
|
||||||
|
String[] split = query.split("=");
|
||||||
|
String paramValue = split[1];
|
||||||
|
//解密请求参数
|
||||||
|
String param =AesCbcUtils.decrypt(paramValue);
|
||||||
|
//使用反射强行拿出 URI 的 query
|
||||||
|
Field targetQuery = uri.getClass().getDeclaredField("query");
|
||||||
|
//授权
|
||||||
|
targetQuery.setAccessible(true);
|
||||||
|
//重新设置参数
|
||||||
|
targetQuery.set(uri, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ spring:
|
||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
username: nacos
|
username: nacos
|
||||||
password: nacos
|
password: Jjsp@nacos2023
|
||||||
namespace: jjzhgd
|
namespace: jjzhgd
|
||||||
# 服务注册地址
|
# 服务注册地址
|
||||||
server-addr: 127.0.0.1:8848
|
server-addr: 127.0.0.1:8848
|
||||||
|
|
@ -32,7 +32,7 @@ spring:
|
||||||
shared-configs:
|
shared-configs:
|
||||||
- vsc-dev.yml
|
- vsc-dev.yml
|
||||||
username: nacos
|
username: nacos
|
||||||
password: nacos
|
password: Jjsp@nacos2023
|
||||||
namespace: jjzhgd
|
namespace: jjzhgd
|
||||||
# server-addr: 10.138.132.188:18848
|
# server-addr: 10.138.132.188:18848
|
||||||
management:
|
management:
|
||||||
|
|
@ -48,4 +48,6 @@ management:
|
||||||
endpoints:
|
endpoints:
|
||||||
env:
|
env:
|
||||||
enable: false
|
enable: false
|
||||||
|
system:
|
||||||
|
jm: false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ public class HumanServiceImpl implements HumanService {
|
||||||
@Resource(name = "HumanManageMapper")
|
@Resource(name = "HumanManageMapper")
|
||||||
private HumanManageMapper mapper;
|
private HumanManageMapper mapper;
|
||||||
|
|
||||||
@Autowired
|
@Resource
|
||||||
private RemoteFileService remoteFileService;
|
private RemoteFileService remoteFileService;
|
||||||
|
|
||||||
@Resource(name = "ValidatorsUtils")
|
@Resource(name = "ValidatorsUtils")
|
||||||
|
|
@ -111,7 +111,7 @@ public class HumanServiceImpl implements HumanService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber(),AesCbcUtils.sKey));
|
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber()));
|
||||||
// 保存人员数据
|
// 保存人员数据
|
||||||
mapper.addOrUpdatePersonnel(vo);
|
mapper.addOrUpdatePersonnel(vo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ public class TeamServiceImpl implements TeamService {
|
||||||
} else {
|
} else {
|
||||||
vo.setType(2);
|
vo.setType(2);
|
||||||
}
|
}
|
||||||
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber(),AesCbcUtils.sKey));
|
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber()));
|
||||||
mapper.addOrUpdateTeam(vo);
|
mapper.addOrUpdateTeam(vo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("新增/修改班组", e);
|
log.error("新增/修改班组", e);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue