JAVA返回前端密文(保护加密信息)

06-01 1451阅读

1.开启加密类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EnableSensitive {
    String type() default "default";
​
}

2.加密字段

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveEncrypt {
    String type() default "default";
}

3.加密工具类

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
​
public class EncryptionUtils {
​
    // 长度必须为16字节(128位),也可用24、32字节(192、256位)
    private static final String SECRET_KEY = "狗头"; // 可配置化
    private static final String ALGORITHM = "AES";
​
    // 加密
    public static String encrypt(String plainText) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }
​
    // 解密
    public static String decrypt(String cipherText) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] decodedBytes = Base64.getDecoder().decode(cipherText);
            byte[] decrypted = cipher.doFinal(decodedBytes);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }
}

4.RequestBody的解析器Spring

​
import com.vt.api.jcc_server.annotation.EnableSensitive;
import com.vt.api.jcc_server.annotation.SensitiveEncrypt;
import com.vt.api.jcc_server.util.EncryptionUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
​
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
​
@RestControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
​
    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType,
                            Class> converterType) {
        return true;
    }
​
    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage,
                                  MethodParameter parameter, Type targetType,
                                  Class> converterType) {
        return body;
    }
​
    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage,
                                           MethodParameter parameter, Type targetType,
                                           Class> converterType)
            throws IOException {
        // 可在这里对原始 JSON 解密
        return inputMessage;
    }
​
    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage,
                                MethodParameter parameter, Type targetType,
                                Class> converterType) {
        decryptFields(body);
        return body;
    }
​
    private void decryptFields(Object obj) {
        if (obj == null) return;
        if (obj.getClass().getAnnotation(EnableSensitive.class) == null) return;
        try {
            for (Field field : obj.getClass().getDeclaredFields()) {
                if (field.isAnnotationPresent(SensitiveEncrypt.class)) {
                    field.setAccessible(true);
                    String encrypted = (String) field.get(obj);
                    if (encrypted != null) {
                        field.set(obj, EncryptionUtils.decrypt(encrypted));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.返回时的解析器Spring

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.vt.api.jcc_server.annotation.EnableSensitive;
import com.vt.api.jcc_server.annotation.SensitiveEncrypt;
import com.vt.api.jcc_server.util.EncryptionUtils;
import com.vt.framework.common.vo.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
​
import java.lang.reflect.Field;
import java.util.Collection;
​
@RestControllerAdvice
public class EncryptResponseAdvice implements ResponseBodyAdvice {
​
    private static final Logger log = LoggerFactory.getLogger(EncryptResponseAdvice.class);
​
    @Override
    public boolean supports(MethodParameter returnType, Class> converterType) {
        return true; // 也可以加条件过滤
    }
​
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result) {
            Object data = ((Result) body).getResult();
​
            // 空 or 基础类型直接返回,不处理
            if (data == null || isPrimitiveOrWrapper(data.getClass())) {
                return body;
            }
​
            // 分页处理
            if (data instanceof IPage) {
                IPage page = (IPage) data;
                for (Object record : page.getRecords()) {
                    encryptFields(record);
                }
            }
            // 集合处理(可能是 List)
            else if (data instanceof Collection) {
                for (Object item : (Collection) data) {
                    encryptFields(item);
                }
            }
            // 单个实体处理
            else {
                encryptFields(data);
            }
        } else {
            // 防止误处理基础类型返回
            if (!isPrimitiveOrWrapper(body.getClass())) {
                encryptFields(body);
            }
        }
        return body;
    }
​
​
​
​
    private void encryptFields(Object obj) {
        if (obj == null) return;
        if (obj.getClass().getAnnotation(EnableSensitive.class) == null) return;
​
​
​
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
​
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(obj);
​
                if (value == null) continue;
​
                if (field.isAnnotationPresent(SensitiveEncrypt.class) && value instanceof String) {
                    String encrypted = EncryptionUtils.encrypt((String) value);
                    field.set(obj, encrypted);
                }
​
                // 递归处理嵌套对象,比如对象里面还有对象
                if (!isPrimitiveOrWrapper(value.getClass())) {
                    encryptFields(value);
                }
​
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private boolean isPrimitiveOrWrapper(Class clazz) {
        return clazz.isPrimitive() ||
                clazz == String.class ||
                Number.class.isAssignableFrom(clazz) ||
                clazz == Boolean.class ||
                clazz == Character.class;
    }
​
​
}

6.用法

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.vt.api.jcc_server.annotation.EnableSensitive;
import com.vt.api.jcc_server.annotation.SensitiveEncrypt;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
​
import java.time.LocalDateTime;
​
/**
 * 特殊日期管理
 * @TableName t_special_date_lib
 */
​
@EqualsAndHashCode(callSuper = true)
@TableName(value ="t_account_investigated")
@Data
@Schema(description = "待调查人员账号")
@EnableSensitive
public class AccountInvestigated   {
​
    @Schema(description = "姓名")
    @SensitiveEncrypt
​
    private String name;
​
    @Schema(description = "银行卡号")
    @SensitiveEncrypt
    private String cardNumber;
    @Schema(description = "银行类型")
    @SensitiveEncrypt
​
    private String type;
    @Schema(description = "备注")
    @SensitiveEncrypt
    private String remark;
​
    @Schema(description = "案件id")
    private String caseId;
​
​
​
    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}
JAVA返回前端密文(保护加密信息)
(图片来源网络,侵删)
JAVA返回前端密文(保护加密信息)
(图片来源网络,侵删)
JAVA返回前端密文(保护加密信息)
(图片来源网络,侵删)
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码