1.引入nbsaas-boot依赖,nbsaas-boot里面已经包括spring boot,spring cloud,spring cloud tencent.
com.nbsaas.boot
nbsaas-boot
1.1.6-2023
2.解密解密原理,主要靠RequestBodyDecodeAdvice,ResponseEncryptionAdvice。EncryptionData注解。
3.具体代码
package com.nbsaas.boot.advice;
import com.nbsaas.boot.rest.annotations.CreateData;
import com.nbsaas.boot.rest.annotations.EncryptionData;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
@RestControllerAdvice
public class RequestBodyDecodeAdvice extends RequestBodyAdviceAdapter {
/**
* 128位的AESkey
*/
public static final byte[] AES_KEY = "+f0DrJTqGXg4BQNtBg1AWA==".getBytes(StandardCharsets.US_ASCII);
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class extends HttpMessageConverter>> converterType) {
/**
* 系统使用的是Gson作为json数据的Http消息转换器
*/
if (targetType instanceof Class>){
CreateData allArgsConstructor= ((Class>)targetType).getAnnotation(CreateData.class);
if (allArgsConstructor!=null){
System.out.println("采用Lombok");
}
EncryptionData encryptionData= methodParameter.getParameterAnnotation(EncryptionData.class);
if (encryptionData!=null){
return true;
}else{
return false;
}
}
return GsonHttpMessageConverter.class.isAssignableFrom(converterType);
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class extends HttpMessageConverter>> converterType) throws IOException {
// 读取加密的请求体
byte[] body = new byte[inputMessage.getBody().available()];
inputMessage.getBody().read(body);
try {
// 使用AES解密
body = this.decrypt(org.apache.commons.codec.binary.Base64.decodeBase64(body), AES_KEY);
} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
| BadPaddingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
// 使用解密后的数据,构造新的读取流
InputStream rawInputStream = new ByteArrayInputStream(body);
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
@Override
public InputStream getBody() throws IOException {
return rawInputStream;
}
};
}
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class extends HttpMessageConverter>> converterType) {
return body;
}
/**
* AES解密
*
* @param data
* @param key
* @return
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] decrypt(byte[] data, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
return cipher.doFinal(data);
}
public byte[] encrypt(byte[] data, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
return cipher.doFinal(data);
}
private 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;
}
}
加密代码
package com.nbsaas.boot.advice;
import com.google.gson.Gson;
import com.nbsaas.boot.rest.annotations.EncryptionData;
import com.nbsaas.boot.rest.response.ResponseObject;
import org.apache.shiro.codec.Base64;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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 javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@ControllerAdvice
public class ResponseEncryptionAdvice implements ResponseBodyAdvice
4.控制器通过注解快速实现加密解密
响应加密
@EncryptionData
@SearchData
@RequiresPermissions("store")
@RequestMapping("/search")
public PageResponse search( @RequestBody StoreSearch request) {
return storeApi.search(request);
}
参数加密
@SearchData
@RequiresPermissions("store")
@RequestMapping("/list")
public ListResponse list(@EncryptionData @RequestBody StoreSearch request) {
return storeApi.list(request);
}
应该其实是不是很简单。