数据加解密
This commit is contained in:
parent
4e67f58655
commit
f16c58f460
|
|
@ -17,10 +17,7 @@ import io.jsonwebtoken.Claims;
|
|||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -56,7 +53,6 @@ public class TokenController {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 本地推出登录
|
||||
* @param request
|
||||
|
|
|
|||
|
|
@ -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位
|
||||
*/
|
||||
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
|
||||
* @return 加密后的密文
|
||||
*/
|
||||
public static String encrypt(String source, String key) throws Exception {
|
||||
byte[] sourceBytes = source.getBytes(ENCODING);
|
||||
byte[] keyBytes = key.getBytes(ENCODING);
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
|
||||
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(ENCODING));
|
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, KEY_ALGORITHM), iv);
|
||||
byte[] decrypted = cipher.doFinal(sourceBytes);
|
||||
return Base64.encodeBase64String(decrypted);
|
||||
public static String encrypt(String source ) {
|
||||
try{
|
||||
String key=sKey;
|
||||
byte[] sourceBytes = source.getBytes(ENCODING);
|
||||
byte[] keyBytes = key.getBytes(ENCODING);
|
||||
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
|
||||
IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(ENCODING));
|
||||
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解密
|
||||
*(CBC模式)
|
||||
* @param encryptStr 加密后的密文
|
||||
* @param data 加密后的密文
|
||||
* @param
|
||||
* @throws Exception
|
||||
* @return 源字符串
|
||||
*/
|
||||
public static String decrypt(String encryptStr) {
|
||||
public static String decrypt(String data) {
|
||||
try{
|
||||
String encryptStr="";
|
||||
if(StringHelper.isNotEmpty(data)){
|
||||
encryptStr=data.replace(" ","+");
|
||||
}
|
||||
String key=sKey;
|
||||
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
|
||||
byte[] keyBytes = key.getBytes(ENCODING);
|
||||
|
|
@ -87,9 +105,10 @@ public class AesCbcUtils {
|
|||
byte[] decoded = cipher.doFinal(sourceBytes);
|
||||
return new String(decoded, ENCODING);
|
||||
}catch (Exception e){
|
||||
log.info("------------------->请求加密参数不正确");
|
||||
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,144 @@
|
|||
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.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 {
|
||||
|
||||
@Override
|
||||
public GatewayFilter apply(Object config) {
|
||||
return (exchange, chain) -> {
|
||||
ServerHttpRequest serverHttpRequest = exchange.getRequest();
|
||||
HttpHeaders header = serverHttpRequest.getHeaders();
|
||||
String decrypt = serverHttpRequest.getHeaders().getFirst("decrypt");
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ public class TeamServiceImpl implements TeamService {
|
|||
} else {
|
||||
vo.setType(2);
|
||||
}
|
||||
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber(),AesCbcUtils.sKey));
|
||||
vo.setIdNumber(AesCbcUtils.encrypt(vo.getIdNumber()));
|
||||
mapper.addOrUpdateTeam(vo);
|
||||
} catch (Exception e) {
|
||||
log.error("新增/修改班组", e);
|
||||
|
|
|
|||
Loading…
Reference in New Issue