1.创建工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
@Slf4j
public class DESUtils {
/** 算法名称 */
private static final String KEY_ALGORITHM = "DES";
/** 算法名称/加密模式/填充方式 */
private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
/** 8位KEY 默认 自定义*/
private static final String DEFAULT_KEY = "SHXPJCHN";
/** 8位IV 默认 自定义*/
private static final String DEFAULT_IV = "JcHn1@34";
/**
* 生成密钥(base64字符串)
*/
public static String initKey() throws NoSuchAlgorithmException, NoSuchProviderException {
// 实例化密钥生成器
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
String name = kg.getProvider().getName();
System.out.println(name);
// 生成密钥
SecretKey secretKey = kg.generateKey();
// 获取二进制密钥编码形式
return Base64.encodeBase64String(secretKey.getEncoded());
}
/**
* 转换密钥
*/
private static Key toKey(String key) throws Exception {
// 实例化Des密钥
DESKeySpec dks = new DESKeySpec(Base64.decodeBase64(key));
// 实例化密钥工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
// 生成密钥
return keyFactory.generateSecret(dks);
}
/**
* 加密数据
*
* @param data 待加密数据
* @param key 密钥(8位字符的base64)
* @param iv 加密向量(8位字符的base64)
* @return 加密后的数据
*/
public static byte[] encrypt(String data, String key, String iv) throws Exception {
// 还原密钥
Key k = toKey(key);
// 实例化Cipher对象,它用于完成实际的加密操作
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.decodeBase64(iv));
// 初始化Cipher对象,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, k, ivParameterSpec);
// 执行加密操作。加密后的结果通常都会用Base64编码进行传输
log.info("加密后字符="+cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
String s= String.valueOf(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
log.info("加密后字符串="+ s);
return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// return encryptBASE64(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
// return Base64.encodeBase64String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
}
public static byte[] encrypt(String data, String key) throws Exception {
String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
return encrypt(data, key, iv);
}
public static byte[] encrypt(String data) throws Exception {
String key = Base64.encodeBase64String(DEFAULT_KEY.getBytes(StandardCharsets.UTF_8));
String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
return encrypt(data, key, iv);
}
/**
* 解密数据
*
* @param
* @param
* @param
* @return 解密后的数据
*/
public static String decrypt(String data, String key, String iv) throws Exception {
Key k = toKey(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.decodeBase64(iv));
// 初始化Cipher对象,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, k, ivParameterSpec);
// 执行解密操作
return new String(cipher.doFinal(Base64.decodeBase64(data)));
}
public static String decrypt(String data) throws Exception {
String key = Base64.encodeBase64String(DEFAULT_KEY.getBytes(StandardCharsets.UTF_8));
String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
return decrypt(data, key, iv);
}
public static String decrypt(String data, String key) throws Exception {
String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
return decrypt(data, key, iv);
}
// Base64解码
public static String encryptBASE64(byte[] data) {
java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
String encode = encoder.encodeToString(data);
return encode;
}
// Base64编码
public static byte[] decryptBASE64(String data) throws Exception {
java.util.Base64.Decoder decoder = java.util.Base64.getDecoder();
byte[] buffer = decoder.decode(data);
return buffer;
}
public static void main(String[] args) throws Exception {
String source = "{trainSubject: 'test1', trainTime: '2021-08-01',trainAddress:'万达广场',receiveTrainPeople:'张三,李四',promoter:'admin'}";
System.out.println("原文: " + source);
String key = initKey();
System.out.println("密钥: " + key);
byte[] encryptData = encrypt("admin");
System.out.println("加密: " + encryptBASE64(encryptData));
String decryptData = decrypt("Y0pF/dxSY5siD9YHxCG1RJaRyux3gPgbTgIRJt8QBe7j+WCwRIG56OP8Duh7JUAq8EERaBF/40awRYz5/4rkY6Eb3C/Db3VSZbIF6Q9lQ1U=");
System.out.println("解密: " + decryptData);
}
}
2.自定义注解
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecurityParameter {
/**
* 入参是否解密,默认不解密
*/
boolean inDecode() default false;
/**
* 出参是否加密,默认不加密
*/
boolean outEncode() default false;
}
3.自定义 EncodeResponseBodyAdvice (返回数据加密)
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shxp.project.utils.DESUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* 返回数据加密
*/
@ControllerAdvice(basePackages = "com.shxp.project")
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {
private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
boolean encode = true;
//指定加注解的方法加密
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
//获取注解配置的包含和去除字段
SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
//出参是否需要加密
encode = serializedField.outEncode();
}
if (encode) {
logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
if (methodParameter.getMethod().getName().contains("Configuration")) {
return body;
}
if (methodParameter.getMethod().getName().contains("swagger")) {
return body;
}
// if (methodParameter.getMethod().getName().contains("get")) {
// return body;
// }
ObjectMapper objectMapper = new ObjectMapper();
try {
// logger.info("返回结果加密1=" + body);
String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
// logger.info("返回结果加密2=" + result);
// logger.info("返回结果加密=" + DESUtils.encrypt(result));
return DESUtils.encrypt(result);
} catch (Exception e) {
e.printStackTrace();
logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
}
}
return body;
}
}
4.自定义 DecodeRequestBodyAdvice (请求数据解密)
import com.shxp.project.utils.DESUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* 请求数据解密
*/
@ControllerAdvice(basePackages = "com.shxp.project")
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {
private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
try {
boolean encode = false;
if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
//获取注解配置的包含和去除字段
SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
//入参是否需要解密
encode = serializedField.inDecode();
}
if (encode) {
logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
return new MyHttpInputMessage(inputMessage);
} else {
return inputMessage;
}
} catch (Exception e) {
e.printStackTrace();
logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
return inputMessage;
}
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return body;
}
class MyHttpInputMessage implements HttpInputMessage {
private HttpHeaders headers;
private InputStream body;
public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
this.headers = inputMessage.getHeaders();
this.body = IOUtils.toInputStream(DESUtils.decrypt(easpString(IOUtils.toString(inputMessage.getBody(), "UTF-8"))), "UTF-8");
}
@Override
public InputStream getBody() throws IOException {
return body;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
/**
* @param requestData
* @return
*/
public String easpString(String requestData) {
if (requestData != null && !requestData.equals("")) {
String s = "{\"requestData\":";
if (!requestData.startsWith(s)) {
throw new RuntimeException("参数【requestData】缺失异常!");
} else {
int closeLen = requestData.length() - 1;
int openLen = "{\"requestData\":".length();
String substring = StringUtils.substring(requestData, openLen, closeLen);
return substring;
}
}
return "";
}
}
}
5.前端相关
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" th:src="@{~/js/aes.js}"></script>
<script type="text/javascript" th:src="@{~/js/pad-zeropadding.js}"></script>
<script type="text/javascript" th:src="@{~/js/security.js}"></script>
<script type="text/javascript" th:src="@{~/js/jquery-2.2.3.min.js}"></script>
<script type="text/javascript" th:src="@{~/js/random.js}"></script>
</head>
<body>
<!--<span th:text="${hello}"></span>-->
<button id="select" onclick="sendData()">触发</button>
</body>
<script>
function sendData() {
// aes秘钥
var privateKey="abcdef0123456789";
// aes加密
var data = Encrypt(JSON.stringify({name:"qiangqiang"}),privateKey);
// 创建json对象
var json = {
"requestData": data
};
$.ajax({
type: "POST",
url:"/testAesEncrypt",
data:JSON.stringify(json),
dataType:'json',
contentType: "application/json",
success: function(result) {
var data = Decrypt(result.requestData,privateKey);
alert("返回的数据:"+data);
}
});
}
</script>
</html>