一,针对请求参数和应答数据都是json格式时,可以通过,下面的方式,进行统一的的加解密。
1. 设置配置文件。
@Bean public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); /** SimpleModule 入参xss处理、返回BigDecimal类型处理 */ SimpleModule module = new SimpleModule("XssStringJsonSerializer"); module.addDeserializer(String.class,new JsonHtmlXssDeserializer(String.class)); objectMapper.registerModule(module); List<MediaType> mediaTypeList = new ArrayList<>(); mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8); jsonConverter.setSupportedMediaTypes(mediaTypeList); jsonConverter.setObjectMapper(objectMapper); return jsonConverter; }
2.编写JsonHtmlXssDeserializer 类,对请求参数进行解密处理。
public class JsonHtmlXssDeserializer extends JsonDeserializer<String> {
private static final String SM4Prefix = "Z@!@$B";
public JsonHtmlXssDeserializer(Class<String> string) {
super();
}
@Override
public Class<String> handledType() {
return String.class;
}
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String value = jsonParser.getValueAsString();
if (value != null) {
if(value.startsWith(SM4Prefix)){
value = value.substring(6);
try {
value = SM4.sm4Decrypt(value);
} catch (IOException e) {
e.printStackTrace();
throw new IOException("json 解密失败");
}
}
return value;
}
return value;
}
}
编写完毕后,只要字符串的前缀为Z@!@$B时,会执行 SM4 的解密程序。
3.编写应当数据统一加密的方法
自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@Target(ElementType.FIELD)
@JsonSerialize(using = EncryptDataSerializer.class)
public @interface EncryptData {
/**
* 加密策略
*/
Strategy strategy() default Strategy.SM4;
Methods methods() default Methods.ENCRYPT;
enum Strategy {
/**
* SM4
*/
SM4,
/**
* AES
*/
AES,
/**
* 从右边开始
*/
RIGHT
}
enum Methods {
/**
* 对字段加,解密
*/
ALL,
/**
* 仅加密
*/
ENCRYPT,
/**
* 仅解密
*/
DECRYPT
}
}
定义aop,真对注解进行处理:
@Component
@Slf4j
@Aspect
public class DecryptAspect {
final static Logger logger = LoggerFactory.getLogger(DecryptAspect.class);
@Before(value = "execution(public * com.ruoyi.project.system.controller.*Controller.*(..))")
public void before(JoinPoint joinPoint) {
Object[] obj = joinPoint.getArgs();
if (null != obj) {
int len = obj.length;
for (int i = 0; i < len; i++) {
Object item = obj[i];
if (item == null) {
return;
}
Field[] fields = item.getClass().getDeclaredFields();
// 遍历所有字段
for (Field field : fields) {
// 若该字段被SecurityParameter注解,则进行解密/加密
Class<?> fieldType = field.getType();
if (fieldType == String.class) {
EncryptData encryptData =AnnotationUtils.findAnnotation(field, EncryptData.class);
if (null != encryptData) {
// 设置private类型允许访问
try {
field.setAccessible(Boolean.TRUE);
handleField(item, field, encryptData);
field.setAccessible(Boolean.FALSE);
}catch (Exception ex){
logger.error("解压失败!",ex.fillInStackTrace());
}
}
}
}
}
}
}
private void handleField(Object item, Field field,EncryptData encryptData) throws Exception {
if (null == item) {
return;
}
if(field.get(item) == null){
return;
}
String str = field.get(item).toString();
final EncryptData.Methods methods = encryptData.methods();
switch (encryptData.strategy()){
case SM4:
try {
if(methods == EncryptData.Methods.ALL ||
methods == EncryptData.Methods.DECRYPT) {
field.set(item,SM4.sm4Decrypt(str));
}
}catch (Exception ex){
logger.error("sm4加密失败",ex.getCause());
}
return;
case AES:
return;
default:
throw new IllegalArgumentException("Illegal Sensitive Strategy");
}
}
}
EncryptDataSerializer 重新序列化接口:
public class EncryptDataSerializer extends JsonSerializer<String> implements ContextualSerializer {
final Logger logger = LoggerFactory.getLogger(EncryptDataSerializer.class);
private EncryptData encryptData;
public EncryptDataSerializer(EncryptData encryptData) {
this.encryptData = encryptData;
}
public EncryptDataSerializer() {
}
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (StringUtils.isBlank(value)) {
gen.writeString(value);
return;
}
if (encryptData != null) {
final EncryptData.Strategy strategy = encryptData.strategy();
final EncryptData.Methods methods = encryptData.methods();
gen.writeString(getValue(value, strategy,methods));
} else {
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
EncryptData annotation = property.getAnnotation(EncryptData.class);
if (annotation != null) {
return new EncryptDataSerializer(annotation);
}
return this;
}
private String getValue(String rawStr, EncryptData.Strategy strategy, EncryptData.Methods methods) {
String strBack="";
switch (strategy) {
case SM4:
try {
if(!StringUtils.isEmpty(rawStr)) {
if(methods == EncryptData.Methods.ALL ||
methods == EncryptData.Methods.ENCRYPT) {
strBack = SM4.sm4Encode(rawStr);
}
}
}catch (Exception ex){
logger.error("sm4加密失败",ex.getCause());
}
return strBack;
case AES:
return rawStr;
default:
throw new IllegalArgumentException("Illegal Sensitive Strategy");
}
}
}
只要在定义的实体类上添加,EncryptData 注解,返回的字段就会sm4进行加密(注意:字段类型必须为String)
如: @EncryptData(strategy = EncryptData.Strategy.SM4,methods = EncryptData.Methods.ALL)
/** 手机号码 */
@Excel(name = "手机号码")
private String phonenumber;
应答信息返回:
phonenumber 字段会进行sm4加密。