对请求响应数据进行加密解密传输

文章目录

  • 项目需求背景
  • 加密方式
  • 具体代码

项目需求背景

本项目本来是围绕app相关的开发,接口都已经开发完了,在之后的需求提出来要在微信公众号也整一套,需要对微信这边的请求响应的数据进行加密解密,还需要满足app这边的请求响应不动。

加密方式

和前端进行商量后,决定使用RSA+AES两种加密算法,因为AES对称加密的效率要比RSA效率高很多,实现的步骤是:

  1. 后端先生成RSA加密算法的公钥和私钥,私钥自己保存,存入redis中,然后将存入redis中的随机生成字符串的key和公钥给前端
  2. 前端生成AES密钥
  3. 前端对请求的数据使用AES密钥进行加密
  4. 然后使用调用后端接口得到的RSA公钥对AES密钥进行加密
  5. 将加密后的AES密钥,以及第一步生成的随机字符串key放入请求头中
  6. 后端先获取请求头中的数据,如果有上面这两个值就表示该请求是微信发送的,请求数据需要解密,如果请求头中没有这两个数据就不需要解密
  7. 解密的具体过程是首先取出请求体中的数据,解密,将解密后的数据放回请求体中
  8. 加密的过程和解密相似

具体代码

RSA加密工具类代码如下:

package com.ncb.mbank.api.framework.web.utils;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/**
 * 

* RSA公钥/私钥/签名工具包 *

*

* 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式
* 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,
* 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 *

* * @author 胡尚 * @date 2022/1/7 14:11 * @version 1.0 */
public class RsaUtil { /** * 加密算法RSA */ public static final String KEY_ALGORITHM = "RSA"; /** * 签名算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; /** * 获取公钥的key */ private static final String PUBLIC_KEY = "RSAPublicKey"; /** * 获取私钥的key */ private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * RSA最大加密明文大小 */ private static final int MAX_ENCRYPT_BLOCK = 117; /** * RSA最大解密密文大小 */ private static final int MAX_DECRYPT_BLOCK = 128; /** *

* 生成密钥对(公钥和私钥) *

* * @return * @throws Exception */
public static Map<String, Object> genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** *

* 用私钥对信息生成数字签名 *

* * @param data * 已加密数据 * @param privateKey * 私钥(BASE64编码) * * @return * @throws Exception */
public static String sign(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(privateK); signature.update(data); return Base64Utils.encode(signature.sign()); } /** *

* 校验数字签名 *

* * @param data * 已加密数据 * @param publicKey * 公钥(BASE64编码) * @param sign * 数字签名 * * @return * @throws Exception * */
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64Utils.decode(sign)); } /** *

* 私钥解密 *

* * @param encryptedData * 已加密数据 * @param privateKey * 私钥(BASE64编码) * @return * @throws Exception */
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** *

* 公钥解密 *

* * @param encryptedData * 已加密数据 * @param publicKey * 公钥(BASE64编码) * @return * @throws Exception */
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; } /** *

* 公钥加密 *

* * @param data * 源数据 * @param publicKey * 公钥(BASE64编码) * @return * @throws Exception */
public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { byte[] keyBytes = Base64Utils.decode(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicK = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** *

* 私钥加密 *

* * @param data * 源数据 * @param privateKey * 私钥(BASE64编码) * @return * @throws Exception */
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_ENCRYPT_BLOCK; } byte[] encryptedData = out.toByteArray(); out.close(); return encryptedData; } /** *

* 获取私钥 *

* * @param keyMap * 密钥对 * @return * @throws Exception */
public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return Base64Utils.encode(key.getEncoded()); } /** *

* 获取公钥 *

* * @param keyMap * 密钥对 * @return * @throws Exception */
public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return Base64Utils.encode(key.getEncoded()); } /** * java端公钥加密 */ public static String encryptedDataOnJava(String data, String PUBLICKEY) { try { data = Base64Utils.encode(encryptByPublicKey(data.getBytes(), PUBLICKEY)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return data; } /** * java端私钥解密 */ public static String decryptDataOnJava(String data, String PRIVATEKEY) { String temp = ""; try { byte[] rs = Base64Utils.decode(data); //以utf-8的方式生成字符串 temp = new String(RsaUtil.decryptByPrivateKey(rs, PRIVATEKEY),"UTF-8"); } catch (Exception e) { e.printStackTrace(); } return temp; } public static void main(String[] args) throws Exception { String s = "hello,您好"; System.out.println("明文:" + s); // 生成密钥对(公钥和私钥) Map<String, Object> stringObjectMap = genKeyPair(); // 获取私钥 String privateKey = getPrivateKey(stringObjectMap); // 获取公钥 String publicKey = getPublicKey(stringObjectMap); System.out.println("公钥:" + publicKey); System.out.println("私钥:" + privateKey); String s1 = encryptedDataOnJava(s, publicKey); System.out.println("使用公钥加密后的数据:" + s1); String s2 = decryptDataOnJava(s1, privateKey); System.out.println("使用私钥解密后的数据:" + s2); } }

接下来写一个接口,让前端获取公钥

package com.ncb.mbank.api.service.openact.bizsvc.impl;

import com.alibaba.fastjson.JSON;
import com.ncb.mbank.api.framework.core.constants.ErrorCodeConstants;
import com.ncb.mbank.api.framework.core.exception.ApplicationException;
import com.ncb.mbank.api.framework.web.constants.HsAccountConst;
import com.ncb.mbank.api.framework.web.utils.MbankHsUtils;
import com.ncb.mbank.api.framework.web.utils.RsaUtil;
import com.ncb.mbank.api.restclient.gateway.feignclient.WeChatFeignClient;
import com.ncb.mbank.api.service.openact.bizsvc.MWeChatTencentBizSvc;
import com.ncb.mbank.api.service.openact.dto.req.GetWeChatSignatureReq;
import com.ncb.mbank.api.service.openact.dto.resp.GetWeChatSignatureResp;
import com.ncb.mbank.api.service.openact.dto.resp.RsaEncryptResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Author 胡尚
 * @Date: 2022/1/4 11:54
 * @Version 1.0
 */
@Service
@Slf4j
public class MWeChatTencentBizSvcImpl implements MWeChatTencentBizSvc {

    /**
     * RSA加密的私钥存入redis中 过期时间设置为10个小时
     */
    private final static Long RSA_PRIVATE_KEY_REDIS_TIMEOUT = 36000L;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public RsaEncryptResp getWeChatRsaPublicKey() throws ApplicationException {
        RsaEncryptResp resp = new RsaEncryptResp();
        try {
            // 生成密钥对(公钥和私钥)
            Map<String, Object> stringObjectMap = RsaUtil.genKeyPair();
            // 获取私钥
            String privateKey = RsaUtil.getPrivateKey(stringObjectMap);
            // 获取公钥
            String publicKey = RsaUtil.getPublicKey(stringObjectMap);

            // 将私钥存入redis中,先创建redis的key    createNonceStr()方法其实就是随机生成一段字符串,这里就不提供了
            String redisKey = HsAccountConst.RSA.concat(MbankHsUtils.createNonceStr());
            stringRedisTemplate.opsForValue().set(redisKey, privateKey, RSA_PRIVATE_KEY_REDIS_TIMEOUT, TimeUnit.SECONDS);

            log.info("存入redis中的私钥为{}",stringRedisTemplate.opsForValue().get(redisKey));

            // 返回数据给前端
            resp.setPublicKey(publicKey);
            resp.setPublicKeyId(redisKey);
        } catch (Exception e) {
            log.info("RSA加密生成公钥私钥 并存入redis中出错");
            throw new ApplicationException(ErrorCodeConstants.CLI_RSA_CREATE_KEY_ERROR);
        }
        return resp;
    }
}

AES加密解密工具类:

package com.ncb.mbank.api.framework.web.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

/**
 * @Description: AES 加密工具类
 * @Author 胡尚
 * @Date: 2022/1/7 10:55
 * @Version 1.0
 */
@SuppressWarnings("restriction")
public class AesUtilsTwo {

    /**
     * aes加密
     * @param str
     * @param key
     * @return
     * @throws Exception
     */
    public static String aesEncrypt(String str, String key) throws Exception {
        if (str == null || key == null) return null;
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES"));
        byte[] bytes = cipher.doFinal(str.getBytes("utf-8"));
        //注意不要采用,会出现回车换行 new BASE64Encoder().encode(bytes);
        return Base64.encodeBase64String(bytes);
    }

    /**
     * aes解密
     * @param str
     * @param key
     * @return
     * @throws Exception
     */
    public static String aesDecrypt(String str, String key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES"));
        byte[] bytes = Base64.decodeBase64(str);
        bytes = cipher.doFinal(bytes);
        return new String(bytes, "utf-8");
    }


    public static void main(String[] args) {

        String content = "{\"mobileType\":\"852\",\"smsBusiType\":\"1\",\"mobile\":\"12342134\"}";
        System.out.println("加密前:" + content);

        String key = "FhDgycCnRPSv8VpT";
        System.out.println("加密密钥和解密密钥:" + key);

        try {
            String encrypt = aesEncrypt(content, key);
            System.out.println("加密后:" + encrypt);


            String decrypt = aesDecrypt(encrypt, key);
            System.out.println("解密后:" + decrypt);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

这里我项目的框架的请求参数格式:

{
  "data": {
    "mobile": "15947586958",
    "mobileType": "86",
    "smsBusiType": "1"
  },
  "lang": "sc"
}

所有的请求数据都是放入在data中,和前端商量后解决,加密后的请求数据如下:

{
  "data": {
    "encrypts": "0pG9Z2yTiTgkFcFDePR3STir3KX9Zrb0A5bt4OzutbnYYUsIjTeThPD9bXqUcPojNzGBv4nAX0e/pBY/YT8Ddw=="
  },
  "lang": "sc"
}

将原来data中的数据放到了encrypts中。

所以这里大家根据自己项目请求参数的实际情况自己决定接下来如何对数据加密解密

加密:
创建一个类,继承RequestBodyAdviceAdapter类,supports()方法返回值决定了beforeBodyRead()方法是否需要执行

package com.ncb.mbank.api.framework.authority.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ncb.mbank.api.framework.web.utils.AesUtilsTwo;
import com.ncb.mbank.api.framework.web.utils.RsaUtil;
import io.lettuce.core.RedisException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @Description: 对微信端提交的请求参数进行解密
 * @Author 胡尚
 * @Date: 2022/1/8 14:31
 * @Version 1.0
 */
@Slf4j
@ControllerAdvice
public class WeChatRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

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

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        log.info("---------------微信测试是否调用了进行解密的 beforeBodyRead()方法");

        HttpHeaders headers = inputMessage.getHeaders();
        List<String> encryptKeyList = headers.get("encryptKey");
        List<String> publicKeyIdList = headers.get("publicKeyId");
        log.info("获取请求头中的内容  encryptKey:{} , publicKeyId{}",encryptKeyList ,publicKeyIdList);

        String requestBody = IOUtils.toString(inputMessage.getBody(), StandardCharsets.UTF_8);
        JSONObject requestBodyJson = JSONObject.parseObject(requestBody);
        log.info("获取请求体中的数据为{}", requestBodyJson);
        JSONObject dataJson = requestBodyJson.getJSONObject("data");
        // 获取加密后的数据
        String encrypts = dataJson.getString("encrypts");
        // 获取AES对称加密的密钥 该密钥目前是通过RSA算法公钥进行加密,需要在接下来的代码对该密码进行解密 然后使用解密后的密钥对数据进行解密
        String encryptKey = encryptKeyList == null ? null : encryptKeyList.get(0);
        // 获取RSA算法私钥存入redis中的key
        String publicKeyId = publicKeyIdList == null ? null : publicKeyIdList.get(0);

        // 首先判断是否有上面的内容 如果没有则表示该数据不用解密
        if (StringUtils.hasLength(encrypts) && StringUtils.hasLength(encryptKey) && StringUtils.hasLength(publicKeyId)) {
            String aesDecryptData = decryptToString(encrypts, encryptKey, publicKeyId);
            // 将解密后的数据放回请求体中
            HashMap<String, Object> hashMap = JSON.parseObject(requestBody, HashMap.class);
            hashMap.put("data", JSONObject.parseObject(aesDecryptData));
            requestBody = JSON.toJSONString(hashMap);
            log.info("解密后请求体中的数据为:{}", requestBody);
        }

        InputStream inputStream = IOUtils.toInputStream(requestBody, StandardCharsets.UTF_8);
        // 返回数据
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() throws IOException {
                return inputStream;
            }

            @Override
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }
        };
    }

    /**
     * 对数据进行解密
     *
     * @param encrypts    加密后的数据
     * @param encryptKey  AES对称加密的密钥
     * @param publicKeyId RSA算法私钥存入redis中的key
     * @return 解密后的数据
     */
    public String decryptToString(String encrypts, String encryptKey, String publicKeyId) throws RedisException {

        String privateKey = stringRedisTemplate.opsForValue().get(publicKeyId);
        if (StringUtils.isEmpty(privateKey)) {
            log.error("RSA加密算法的私钥以在缓存中过期");
            throw new RedisException("RSA加密算法的私钥以在缓存中过期");
        }

        // 使用私钥对AES的密钥进行解密
        String aesPassword = RsaUtil.decryptDataOnJava(encryptKey, privateKey);
        log.info("解密后的AES密钥为{}", aesPassword);

        // 使用AES密钥对数据进行解密
        String data = null;
        try {
            data = AesUtilsTwo.aesDecrypt(encrypts, aesPassword);
        } catch (Exception ignored) {
        }
        log.info("使用AES密码解密后的数据为{}", data);
        return data;
    }
}

接下来是对响应的数据进行加密:

package com.ncb.mbank.api.framework.authority.interceptor;

import com.alibaba.fastjson.JSON;
import com.ncb.mbank.api.framework.web.utils.AesUtilsTwo;
import com.ncb.mbank.api.framework.web.utils.RsaUtil;
import io.lettuce.core.RedisException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.List;

/**
 * @Description: 对微信端 响应的数据进行加密
 * @Author 胡尚
 * @Date: 2022/1/10 10:29
 * @Version 1.0
 */
@Slf4j
@ControllerAdvice
public class WeChatResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

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

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        log.info("-------------测试微信 对响应体内容加密的方法是否执行");
        HttpHeaders headers = serverHttpRequest.getHeaders();
        List<String> encryptKeyHeadList = headers.get("encryptKey");
        List<String> publicKeyIdHeadList = headers.get("publicKeyId");
        log.info("请求体中 encryptKey:{},publicKeyId:{}",encryptKeyHeadList,publicKeyIdHeadList);

        if (encryptKeyHeadList == null|| publicKeyIdHeadList == null){
            // 如果请求头中没有这两个 就表示不需要进行加密传输
            return o;
        }
        String encryptKeyHead = encryptKeyHeadList.get(0);
        String publicKeyIdHead = publicKeyIdHeadList.get(0);

        String privateKey = stringRedisTemplate.opsForValue().get(publicKeyIdHead);
        if (StringUtils.isEmpty(privateKey)) {
            log.error("RSA加密算法的私钥以在缓存中过期");
            throw new RedisException("RSA加密算法的私钥以在缓存中过期");
        }

        // 使用私钥对AES的密钥进行解密
        String aesPassword = RsaUtil.decryptDataOnJava(encryptKeyHead, privateKey);
        log.info("解密后的AES密钥为{}", aesPassword);

        String responseBodyStr = JSON.toJSONString(o);
        String responseBodyDecrypt = null;
        try {
            responseBodyDecrypt = AesUtilsTwo.aesEncrypt(responseBodyStr, aesPassword);
        } catch (Exception e) {
        }
        log.info("响应体加密前的内容为:{}\n加密后的内容为:{}",responseBodyStr,responseBodyDecrypt);
        return responseBodyDecrypt;
    }
}

这里也是自己坑了自己,如果那时候可以前端商量,直接将请求体中所有的数据都进行加密,而不是仅仅加密data中的数据就可以在对请求数据解密时少一些工作。

你可能感兴趣的:(java问题解决方案,前端,java,安全)