提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
本公司项目要求越来越严格,并且其中一条为加密,要求请求参数和返回值加密。今天简单的记录
加密传输使用前端加密,后端解密的方式。后端加密前端解密的方式。并且加密后不能被普通工具解密,需要使用密钥进行解密,保证数据的安全。那么现在encrypt-spring-boot-starter可以直接使用。
查看该依赖的源码,发现,只有使用依赖自定的res工具类包装返回值,并且他支持加密方式为AES,并不满足我们项目使用SM2的要求,同时,无法自定义加密方式。所以选择根据他的代码进行改造
首先,需要知道,我们通过在接口上进行注解的方式,来定义改接口是否使用加密和解密。那么首先定义加密和解密的注解
//加密
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.PARAMETER})
public @interface Decrypt {
}
//解密
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Encrypt {
}
使用aop进行切面解密和加密
package com.hisw.talent.encrypt;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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.RequestBodyAdviceAdapter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;/*** @description:接口解密* @date 2022/11/25 14:03*/
@EnableConfigurationProperties(EncryptProperties.class)
@ControllerAdvice
public class DecryptRequest extends RequestBodyAdviceAdapter {@AutowiredEncryptProperties encryptProperties; public DecryptRequest() {}public boolean supports(MethodParameter methodParameter, Type targetType, Class extends HttpMessageConverter>> converterType) {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 {//this.encryptProperties.getKey() 这个key 根据你使用的加密方式来自定义AES需要满足16位,当然//AESUtils.decrypt 可以替换为你需要的加密工具类,比如使用SM2,或者RSA非对称加密byte[] decrypt = AESUtils.decrypt(body, this.encryptProperties.getKey().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);}}
}
package com.hisw.talent.encrypt;import com.fasterxml.jackson.databind.ObjectMapper;
import com.hisw.talent.common.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
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;/*** @description:接口加密* @date 2022/11/25 14:02*/
@EnableConfigurationProperties(EncryptProperties.class)
@ControllerAdvice
public class EncryptResponse implements ResponseBodyAdvice {private ObjectMapper om = new ObjectMapper();@AutowiredEncryptProperties encryptProperties;public EncryptResponse() {}public boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType) {return returnType.hasMethodAnnotation(Encrypt.class);}public Result beforeBodyWrite(Result body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {byte[] keyBytes = this.encryptProperties.getKey().getBytes();try {
/* if (body.getMsg() != null) {body.setMsg(org.javaboy.encrypt.starter.utils.AESUtils.encrypt(body.getMsg().getBytes(), keyBytes));}*/if (body.getData() != null) {//这个步骤可以替换为你的工具类 ,同时 Result 返回工具类替换为你项目中的body.setData(AESUtils.encrypt(this.om.writeValueAsBytes(body.getData()), keyBytes));}} catch (Exception var9) {var9.printStackTrace();}return body;}
}
最后,在你controller 里 打上 注解来控制接口的加密和解密
方式为切面编程,难度不大,但是目前有个问题,AES加密 一旦 body数据太大,那么解密时会出现失败的情况,提示长度需要为16的倍数。RSA加密boby太长,需要使用分段解密。同时会造成前端解密后出现乱码的情况。SM2加密,同样会遇到解密失败的情况。需要04开头,但是过程中依然会报错。希望知道的同学解惑
下一篇:数组与字符串总结