新增股票列表返回加密处理
This commit is contained in:
119
src/main/java/cn/stock/market/utils/AESUtil.java
Normal file
119
src/main/java/cn/stock/market/utils/AESUtil.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package cn.stock.market.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* AES工具类
|
||||
* @author lxiaol
|
||||
* @date 2021年12月23日 13:58
|
||||
*/
|
||||
public class AESUtil {
|
||||
/**
|
||||
* 128位的AESkey
|
||||
*/
|
||||
private static final byte[] AES_KEY = PropertiesUtil.getProperty("aes.key","Jy112211Kj112211").getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
/**
|
||||
* AES解密
|
||||
*
|
||||
* @param data 待解密内容
|
||||
* @return 字节数组
|
||||
*/
|
||||
public static byte[] decrypt(byte[] data) throws InvalidKeyException, NoSuchAlgorithmException,
|
||||
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
|
||||
Cipher cipher = getCipher(AES_KEY, Cipher.DECRYPT_MODE);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 加密操作
|
||||
*
|
||||
* @param data 待加密内容
|
||||
* @return 字节数组
|
||||
*/
|
||||
public static byte[] encrypt(byte[] data) throws InvalidKeyException, NoSuchAlgorithmException,
|
||||
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
|
||||
Cipher cipher = getCipher(AES_KEY, Cipher.ENCRYPT_MODE);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AES 加密操作
|
||||
*
|
||||
* @param text 待加密内容
|
||||
* @return Base64转码后的加密数据
|
||||
*/
|
||||
public static String encrypt(String text) {
|
||||
byte[] byteContent = text.getBytes(StandardCharsets.UTF_8);
|
||||
try {
|
||||
byte[] result = encrypt(byteContent);// 加密
|
||||
return Base64.encode(result);//通过Base64转码返回
|
||||
} catch (Exception e) {
|
||||
// log.info("Error message: {}", e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* AES 解密操作
|
||||
*
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static String decrypt(String text) {
|
||||
byte[] bytes = Base64.decode(text);
|
||||
try {
|
||||
byte[] result = decrypt(bytes);
|
||||
return new String(result, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
// log.info("Error message: {}", e.getMessage());
|
||||
e.printStackTrace();
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取加密器
|
||||
* @param key
|
||||
* @param model
|
||||
* @return
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws NoSuchPaddingException
|
||||
* @throws InvalidKeyException
|
||||
*/
|
||||
private static Cipher getCipher(byte[] key, int model)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(model, secretKeySpec);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String s = "{\n" +
|
||||
" \"mobile\": \"17570717251\",\n" +
|
||||
" \"password\": \"Dd112211\",\n" +
|
||||
" \"platType\": 1,\n" +
|
||||
" \"loginType\": 0,\n" +
|
||||
" \"sourceType\": 1,\n" +
|
||||
" \"equipmentModel\": \"IPHONE\",\n" +
|
||||
" \"version\":1\n" +
|
||||
"}";
|
||||
System.out.println(encrypt(s));
|
||||
System.out.println("Dd112211Ds112211".length());
|
||||
System.out.println(decrypt("Z3aCERCWi+nDUzv67h1/8PqS3CCuCgoj/YRTzkFNa0aNRvagi+wxpj9RsutL7nk2oo65ypyEYbjQXCI8fze8V4kMoVAb2rmoXqO3/DudVeTtY1J2784eXw+DS1QWZlZeHAHKiBaEwLcYe4XcsU9tpQIu6fE6cuSPGNetwN3C7qg6/78t4yUjCf49WW7u0/kErfgsSjMajGaVV/LOg74d2RlUcVBIIq6Us8JW3fFWPQA="));
|
||||
}
|
||||
|
||||
}
|
||||
53
src/main/java/cn/stock/market/utils/StreamUtil.java
Normal file
53
src/main/java/cn/stock/market/utils/StreamUtil.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package cn.stock.market.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 流工具类
|
||||
* @author zhouyl
|
||||
* @date 2023年12月09日 15:11
|
||||
*/
|
||||
@Slf4j
|
||||
public class StreamUtil {
|
||||
private static final Integer BUFFER_SIZE = 128;
|
||||
|
||||
/**
|
||||
* 将requestBody的数据转成字符串
|
||||
*
|
||||
* @param inputStream
|
||||
* @return
|
||||
*/
|
||||
public static String getBodyString(InputStream inputStream) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
if (Objects.nonNull(inputStream)) {
|
||||
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
int bytesRead;
|
||||
char[] charBuffer = new char[BUFFER_SIZE];
|
||||
while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
|
||||
stringBuilder.append(charBuffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("get body fail,{}", e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (bufferedReader != null) {
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cn.stock.market.web.annotations.EncryptFilter;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiImplicitParams;
|
||||
@@ -134,6 +135,7 @@ public class StockApiController {
|
||||
@RequestMapping({"getINDStockList.do"})
|
||||
@ApiOperation(value = "印度股票列表", httpMethod = "GET")
|
||||
@ResponseBody
|
||||
@EncryptFilter(decryptRequest = false)
|
||||
public ServerResponse getINDStockList(@RequestParam("pageSize") Integer pageSize, @RequestParam("pageNum") Integer pageNum) throws IOException {
|
||||
return ServerResponse.createBySuccess(InvestingInvokerApis.of().__page(pageNum, pageSize));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.stock.market.web.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface EncryptFilter {
|
||||
|
||||
/**
|
||||
* 对入参是否解密
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
boolean decryptRequest() default true;
|
||||
|
||||
/**
|
||||
* 对出参是否加密
|
||||
*/
|
||||
boolean encryptResponse() default true;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package cn.stock.market.web.handler;
|
||||
|
||||
import cn.stock.market.utils.AESUtil;
|
||||
import cn.stock.market.utils.StreamUtil;
|
||||
import cn.stock.market.web.annotations.EncryptFilter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 全局请求入参(RequestBody)处理器
|
||||
*
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalRequestBodyHandler extends RequestBodyAdviceAdapter {
|
||||
|
||||
/**
|
||||
* 该方法用于判断当前请求,是否要执行beforeBodyRead方法
|
||||
*
|
||||
* @param methodParameter handler方法的参数对象
|
||||
* @param targetType handler方法的参数类型
|
||||
* @param converterType 将会使用到的Http消息转换器类类型
|
||||
* @return 返回true则会执行beforeBodyRead
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
Method method = methodParameter.getMethod();
|
||||
if (Objects.nonNull(method)) {
|
||||
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
|
||||
if (Objects.nonNull(encryptFilter)) {
|
||||
return encryptFilter.decryptRequest();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在Http消息转换器执转换,之前执行
|
||||
*
|
||||
* @param inputMessage 客户端的请求数据
|
||||
* @param methodParameter handler方法的参数对象
|
||||
* @param targetType handler方法的参数类型
|
||||
* @param converterType 将会使用到的Http消息转换器类类型
|
||||
* @return 返回 一个自定义的HttpInputMessage
|
||||
*/
|
||||
@Override
|
||||
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
|
||||
|
||||
// 读取加密的请求体
|
||||
InputStream body = inputMessage.getBody();
|
||||
HttpHeaders headers = inputMessage.getHeaders();
|
||||
headers.remove("Content-Length");
|
||||
String s = StreamUtil.getBodyString(body);
|
||||
log.info("解密前请求body:" + s);
|
||||
if (StringUtils.isEmpty(s)){
|
||||
return inputMessage;
|
||||
}
|
||||
Method method = methodParameter.getMethod();
|
||||
if (Objects.isNull(method)) {
|
||||
return inputMessage;
|
||||
}
|
||||
// 解密请求
|
||||
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
|
||||
if (Objects.nonNull(encryptFilter) && encryptFilter.decryptRequest()) {
|
||||
// 使用AES解密
|
||||
String bodyDec = AESUtil.decrypt(s);
|
||||
log.info("解密后请求body:" + bodyDec);
|
||||
if (!StringUtils.isEmpty(bodyDec)) {
|
||||
// 使用解密后的数据,构造新的读取流
|
||||
InputStream inputStream = new ByteArrayInputStream(bodyDec.getBytes(StandardCharsets.UTF_8));
|
||||
return new HttpInputMessage() {
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return inputMessage.getHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() {
|
||||
return inputStream;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return inputMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cn.stock.market.web.handler;
|
||||
|
||||
import cn.stock.market.utils.AESUtil;
|
||||
import cn.stock.market.utils.PropertiesUtil;
|
||||
import cn.stock.market.web.annotations.EncryptFilter;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 全局响应结果(ResponseBody)处理器
|
||||
*
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
|
||||
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public GlobalResponseBodyHandler(){
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullableProblems") // 避免 IDEA 警告
|
||||
public boolean supports(MethodParameter returnType, Class converterType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullableProblems") // 避免 IDEA 警告
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
Method method = returnType.getMethod();
|
||||
if (Objects.isNull(body) || Objects.isNull(method)) {
|
||||
return body;
|
||||
}
|
||||
log.info("处理请求地址:{} 的返回值", request.getURI());
|
||||
//获取请求数据
|
||||
String srcData = null;
|
||||
try {
|
||||
srcData = objectMapper.writeValueAsString(body);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
log.info("加密前响应body={}", srcData);
|
||||
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
|
||||
if (Objects.nonNull(encryptFilter) && encryptFilter.encryptResponse()) {
|
||||
//加密
|
||||
String returnStr = AESUtil.encrypt(srcData);
|
||||
log.info("加密后响应body:" + returnStr);
|
||||
//添加 encrypt 告诉前端数据已加密
|
||||
return returnStr;
|
||||
}
|
||||
return body;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -113,3 +113,4 @@ website.domain.url=http://www.huijuwang888.com
|
||||
website.token=0DC8F78384C7AAFF3192A9C60A473FEE7F89C62888689616B98A06910E86B510
|
||||
|
||||
news.main.url=http://eminfo.eastmoney.com
|
||||
aes.key=Jy112211Kj112211
|
||||
|
||||
Reference in New Issue
Block a user