Spring Boot 使用AES前后端传递参数加解密

1.创建工具类


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;

@Slf4j
public class DESUtils {
    /** 算法名称 */
    private static final String KEY_ALGORITHM = "DES";

    /** 算法名称/加密模式/填充方式 */
    private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";

    /** 8位KEY 默认 自定义*/
    private static final String DEFAULT_KEY = "SHXPJCHN";
    /** 8位IV 默认 自定义*/
    private static final String DEFAULT_IV = "JcHn1@34";

    /**
     * 生成密钥(base64字符串)
     */
    public static String initKey() throws NoSuchAlgorithmException, NoSuchProviderException {
        // 实例化密钥生成器
        KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
        String name = kg.getProvider().getName();
        System.out.println(name);
        // 生成密钥
        SecretKey secretKey = kg.generateKey();
        // 获取二进制密钥编码形式
        return Base64.encodeBase64String(secretKey.getEncoded());
    }

    /**
     * 转换密钥
     */
    private static Key toKey(String key) throws Exception {
        // 实例化Des密钥
        DESKeySpec dks = new DESKeySpec(Base64.decodeBase64(key));
        // 实例化密钥工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        // 生成密钥
        return keyFactory.generateSecret(dks);
    }

    /**
     * 加密数据
     *
     * @param data 待加密数据
     * @param key  密钥(8位字符的base64)
     * @param iv   加密向量(8位字符的base64)
     * @return 加密后的数据
     */
    public static byte[] encrypt(String data, String key, String iv) throws Exception {
        // 还原密钥
        Key k = toKey(key);
        // 实例化Cipher对象,它用于完成实际的加密操作
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.decodeBase64(iv));
        // 初始化Cipher对象,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, k, ivParameterSpec);
        // 执行加密操作。加密后的结果通常都会用Base64编码进行传输
        log.info("加密后字符="+cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
        String s= String.valueOf(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
        log.info("加密后字符串="+  s);
        return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
//        return encryptBASE64(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
//        return Base64.encodeBase64String(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
    }

    public static byte[] encrypt(String data, String key) throws Exception {
        String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
        return encrypt(data, key, iv);
    }

    public static byte[] encrypt(String data) throws Exception {
        String key = Base64.encodeBase64String(DEFAULT_KEY.getBytes(StandardCharsets.UTF_8));
        String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
        return encrypt(data, key, iv);
    }

    /**
     * 解密数据
     *
     * @param
     * @param
     * @param
     * @return 解密后的数据
     */
    public static String decrypt(String data, String key, String iv) throws Exception {
        Key k = toKey(key);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.decodeBase64(iv));
        // 初始化Cipher对象,设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, k, ivParameterSpec);
        // 执行解密操作
        return new String(cipher.doFinal(Base64.decodeBase64(data)));
    }

    public static String decrypt(String data) throws Exception {
        String key = Base64.encodeBase64String(DEFAULT_KEY.getBytes(StandardCharsets.UTF_8));
        String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
        return decrypt(data, key, iv);
    }

    public static String decrypt(String data, String key) throws Exception {
        String iv = Base64.encodeBase64String(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
        return decrypt(data, key, iv);
    }

    // Base64解码
    public static String encryptBASE64(byte[] data) {
        java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
        String encode = encoder.encodeToString(data);
        return encode;
    }

    // Base64编码
    public static byte[] decryptBASE64(String data) throws Exception {
        java.util.Base64.Decoder decoder = java.util.Base64.getDecoder();
        byte[] buffer = decoder.decode(data);
        return buffer;
    }

    public static void main(String[] args) throws Exception {
        String source = "{trainSubject: 'test1', trainTime: '2021-08-01',trainAddress:'万达广场',receiveTrainPeople:'张三,李四',promoter:'admin'}";
        System.out.println("原文: " + source);

        String key = initKey();
        System.out.println("密钥: " + key);

        byte[] encryptData = encrypt("admin");

        System.out.println("加密: " + encryptBASE64(encryptData));

        String decryptData = decrypt("Y0pF/dxSY5siD9YHxCG1RJaRyux3gPgbTgIRJt8QBe7j+WCwRIG56OP8Duh7JUAq8EERaBF/40awRYz5/4rkY6Eb3C/Db3VSZbIF6Q9lQ1U=");
        System.out.println("解密: " + decryptData);
    }
}

2.自定义注解


import org.springframework.web.bind.annotation.Mapping;

import java.lang.annotation.*;


@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecurityParameter {

    /**
     * 入参是否解密,默认不解密
     */
    boolean inDecode() default false;

    /**
     * 出参是否加密,默认不加密
     */
    boolean outEncode() default false;
}

3.自定义 EncodeResponseBodyAdvice (返回数据加密)


import com.fasterxml.jackson.databind.ObjectMapper;
import com.shxp.project.utils.DESUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
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;

/**
 * 返回数据加密
 */
@ControllerAdvice(basePackages = "com.shxp.project")
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice {

    private final static Logger logger = LoggerFactory.getLogger(EncodeResponseBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        boolean encode = true;
        //指定加注解的方法加密
        if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
            //获取注解配置的包含和去除字段
            SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
            //出参是否需要加密
            encode = serializedField.outEncode();
        }
        if (encode) {
            logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行加密");
            if (methodParameter.getMethod().getName().contains("Configuration")) {
                return body;
            }
            if (methodParameter.getMethod().getName().contains("swagger")) {
                return body;
            }
//            if (methodParameter.getMethod().getName().contains("get")) {
//                return body;
//            }
            ObjectMapper objectMapper = new ObjectMapper();
            try {
//                logger.info("返回结果加密1=" + body);
                String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(body);
//                logger.info("返回结果加密2=" + result);
//                logger.info("返回结果加密=" + DESUtils.encrypt(result));
                return DESUtils.encrypt(result);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
            }
        }
        return body;
    }
}

4.自定义 DecodeRequestBodyAdvice (请求数据解密)


import com.shxp.project.utils.DESUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestBodyAdvice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

/**
 *  请求数据解密
 */
@ControllerAdvice(basePackages = "com.shxp.project")
public class DecodeRequestBodyAdvice implements RequestBodyAdvice {

    private static final Logger logger = LoggerFactory.getLogger(DecodeRequestBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
        try {
            boolean encode = false;
            if (methodParameter.getMethod().isAnnotationPresent(SecurityParameter.class)) {
                //获取注解配置的包含和去除字段
                SecurityParameter serializedField = methodParameter.getMethodAnnotation(SecurityParameter.class);
                //入参是否需要解密
                encode = serializedField.inDecode();
            }
            if (encode) {
                logger.info("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密");
                return new MyHttpInputMessage(inputMessage);
            } else {
                return inputMessage;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("对方法method :【" + methodParameter.getMethod().getName() + "】返回数据进行解密出现异常:" + e.getMessage());
            return inputMessage;
        }
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    class MyHttpInputMessage implements HttpInputMessage {
        private HttpHeaders headers;

        private InputStream body;

        public MyHttpInputMessage(HttpInputMessage inputMessage) throws Exception {
            this.headers = inputMessage.getHeaders();
            this.body = IOUtils.toInputStream(DESUtils.decrypt(easpString(IOUtils.toString(inputMessage.getBody(), "UTF-8"))), "UTF-8");
        }

        @Override
        public InputStream getBody() throws IOException {
            return body;
        }

        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }

        /**
         * @param requestData
         * @return
         */
        public String easpString(String requestData) {
            if (requestData != null && !requestData.equals("")) {
                String s = "{\"requestData\":";
                if (!requestData.startsWith(s)) {
                    throw new RuntimeException("参数【requestData】缺失异常!");
                } else {
                    int closeLen = requestData.length() - 1;
                    int openLen = "{\"requestData\":".length();
                    String substring = StringUtils.substring(requestData, openLen, closeLen);
                    return substring;
                }
            }
            return "";
        }
    }
}

5.前端相关

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script type="text/javascript" th:src="@{~/js/aes.js}"></script>
    <script type="text/javascript" th:src="@{~/js/pad-zeropadding.js}"></script>
    <script type="text/javascript" th:src="@{~/js/security.js}"></script>
    <script type="text/javascript" th:src="@{~/js/jquery-2.2.3.min.js}"></script>
    <script type="text/javascript" th:src="@{~/js/random.js}"></script>
</head>
<body>
<!--<span th:text="${hello}"></span>-->
<button id="select" onclick="sendData()">触发</button>
</body>
<script>
    function sendData() {
        // aes秘钥
        var privateKey="abcdef0123456789";
        // aes加密
        var data = Encrypt(JSON.stringify({name:"qiangqiang"}),privateKey);
        // 创建json对象
        var json = {
            "requestData": data
        };
        $.ajax({
            type: "POST",
            url:"/testAesEncrypt",
            data:JSON.stringify(json),
            dataType:'json',
            contentType: "application/json",
            success: function(result) {
                var data = Decrypt(result.requestData,privateKey);
                alert("返回的数据:"+data);
            }
        });
    }
</script>
</html>

引入js文件:

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟进军大神陆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值