一.设计
- 添加自定义注解
@Encrypt @Decrypt
加解密注解 - 实现加密方法
- 使用 @ControllerAdvice + RequestBodyAdviceAdapter 处理request进行解密,使用 @ControllerAdvice + ResponseBodyAdvice 对response进行加密
- 在需要加解密的接口上添加注解
二.自定义注解@Encrypt
@Decrypt
加解密注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Encrypt {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.PARAMETER})
public @interface Decrypt {
}
三.实现加密方法
/**
* AES加密/解密
*/
public class AESUtils {
private static final String CHARSET_NAME = "UTF-8";
private static final String AES_NAME = "AES";
// 加密模式
public static final String ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* 加密方法
* @param parload 明文
* @param key 加密秘鑰 32位
* @param iv 偏移量 16位
* @return 密文
*
*/
public static String encrypt(String parload, String key, String iv) {
String result = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
//加密后使用Base64將AES256 加密後的字節碼轉為字符串,再將字符串URLEncode處理
result = URLEncoder.encode(Base64.encodeBase64String(cipher.doFinal(parload.getBytes(CHARSET_NAME))), CHARSET_NAME);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 加密方法
* @param parload 密文
* @param key 加密秘鑰 32位
* @param iv 偏移量 16位
* @return 明文
*/
public static String decrypt(String parload, String key, String iv) {
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET_NAME), AES_NAME);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
//先使用URLDecode解密,然后使用Base64解碼處理,在进行AES解密
return new String(cipher.doFinal(Base64.decodeBase64(URLDecoder.decode(parload, CHARSET_NAME))), CHARSET_NAME);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
四.实现RequestBodyAdvice、ResponseBodyAdvice 接口
@ControllerAdvice
public class EncryptResponse implements ResponseBodyAdvice<Object> {
@Value("${rsa.publicKey}")
private String publicKey;
public EncryptResponse() {
}
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//如果需要对所有api加解密,这里直接 return true;
return returnType.hasMethodAnnotation(Encrypt.class);
}
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
try {
return AESUtils.encrypt(JsonUtils.toJson(body), privateKey, iv);
} catch (Exception var9) {
var9.printStackTrace();
}
return null;
}
}
@ControllerAdvice
public class DecryptRequest extends RequestBodyAdviceAdapter {
@Value("${rsa.privateKey}")
private String privateKey;
public DecryptRequest() {
}
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
//如果需要对所有api加解密,这里直接 return true;
return methodParameter.hasMethodAnnotation(Decrypt.class) || methodParameter.hasParameterAnnotation(Decrypt.class);
}
public HttpInputMessage beforeBodyRead(final 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/CBC/PKCS5Padding加密
byte[] decrypt = AESUtils.decrypt(new String(body), privateKey, iv).getBytes();
final ByteArrayInputStream bais = new ByteArrayInputStream(decrypt);
return new HttpInputMessage() {
public InputStream getBody() throws IOException {
return bais;
}
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
};
} catch (Exception var8) {
var8.printStackTrace();
return super.beforeBodyRead(inputMessage, parameter, targetType, converterType);
}
}
}
五.在需要加解密的方法上加上注解
@RestController
public class StudentController {
private static final Logger logger = LoggerFactory.getLogger(StudentController.class);
@Decrypt@Encrypt
@PostMapping("/student")
private ResponseObject save(@RequestBody Student student) {
logger.info("student:"+ JsonUtils.toJson(student));
return new ResponseObject(200, "success", student);
}
@Decrypt@Encrypt
@PutMapping("/student")
private ResponseObject update(@RequestBody Student student) {
logger.info("student:"+ JsonUtils.toJson(student));
return new ResponseObject(200, "success", student);
}
@Decrypt@Encrypt
@GetMapping("/student")
private ResponseObject list() {
List<Student> students = new ArrayList<>();
students.add(new Student("張三",20));
students.add(new Student("李四",21));
students.add(new Student("王二小",22));
return new ResponseObject(200, "success", students);
}
}