栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录

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

项目需求背景

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

加密方式

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

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

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;


public class RsaUtil {

    
    public static final String KEY_ALGORITHM = "RSA";


    
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";


    
    private static final String PUBLIC_KEY = "RSAPublicKey";


    
    private static final String PRIVATE_KEY = "RSAPrivateKey";


    
    private static final int MAX_ENCRYPT_BLOCK = 117;


    
    private static final int MAX_DECRYPT_BLOCK = 128;


    
    public static Map 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 keyMap = new HashMap(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }


    
    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());
    }


    
    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));
    }


    
    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;
    }


    
    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;
    }


    
    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;
    }

    
    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;
    }


    
    public static String getPrivateKey(Map keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return base64Utils.encode(key.getEncoded());
    }


    
    public static String getPublicKey(Map keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return base64Utils.encode(key.getEncoded());
    }

    
    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;
    }

    
    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 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;


@Service
@Slf4j
public class MWeChatTencentBizSvcImpl implements MWeChatTencentBizSvc {

    
    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 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;


@SuppressWarnings("restriction")
public class AesUtilsTwo {

    
    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);
    }

    
    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.*;


@Slf4j
@ControllerAdvice
public class WeChatRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

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

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

        HttpHeaders headers = inputMessage.getHeaders();
        List encryptKeyList = headers.get("encryptKey");
        List 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 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();
            }
        };
    }

    
    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;


@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 encryptKeyHeadList = headers.get("encryptKey");
        List 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中的数据就可以在对请求数据解密时少一些工作。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704083.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号