全后端交互数据加密
前后端交互
- 通信请求使用https
- 对请求参数进行签名,防止数据篡改
- 对请求参数以及响应数据进行加解密
- app中使用ssl pinning防止抓包操作
https协议
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78n9M2PH-1677252127361)(安全.assets/https加密流程.jpg)]
签名参数
加签和验签:发送方将请求参数通过加密算法生成一个sign值,放到请求参数里;接收方收到请求后,使用同样的方式对请求参数进行加密得到一个sign值,只要两个sign值相同,就说明参数没有被篡改。
加签操作步骤:
- 将所有参数(除了sign本身,以及值是空的参数)按参数键字母升序排序。
- 然后把排序后的参数按 参数1值1 参数2值2 … 参数n值n 的方式拼接成一个字符串。
- 在上一步得到的字符串前面加上密钥key,然后计算md5值,得到32位字符串,然后转成大写,得到的字符串作为sign的值放到请求参数里。
验签操作步骤:
同 加签操作步骤
现在假设需要传输的数据:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn(实际情况最好是通过post方式发送)
- 拼接字符串,首先去除值是空的参数p3,剩下p2=v2&p1=v1&method=cancel&pn=vn,然后按参数名字符升序排序得到字符串:method=cancel&p1=v1&p2=v2&pn=vn。
- 然后做参数名和值的拼接,最后得到methodcancelp1v1p2v2pnvn。
- 在上面拼接得到的字符串前面加上验证密钥key,假设是abc,得到新的字符串abcmethodcancelp1v1p2v2pnvn。
- 将上面得到的字符串进行md5计算,假设得到的是abcdef,然后转为大写,得到ABCDEF这个值即为sign签名值。最终产生的url应该如下:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn&sign=ABCDEF
MD5加密:
public String getSignMD5(String param, String sign) {StringBuffer str = new StringBuffer(sign);if(StringUtils.isNotEmpty(param)){JSONObject obj = JSONObject.parseObject(param);List<String> keys = new ArrayList<String>(obj.keySet());keys.remove(ApiSignUtil.SIGN);Collections.sort(keys);for (String key : keys) {Object value = obj.get(key);if (value == null) {value = "";}str.append(value);}}return getMd5(str.toString());
}public String getMd5(String plainText) {try {MessageDigest md = MessageDigest.getInstance("MD5");md.update(plainText.getBytes());byte[] b = md.digest();StringBuilder buf = new StringBuilder();byte[] var5 = b;int var6 = b.length;for(int var7 = 0; var7 < var6; ++var7) {byte aB = var5[var7];int i = aB;if (aB < 0) {i = aB + 256;}if (i < 16) {buf.append("0");}buf.append(Integer.toHexString(i));}return buf.toString();} catch (NoSuchAlgorithmException var9) {var9.printStackTrace();return "";}
}
加解密请求响应数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfRrbNux-1677252127362)(安全.assets/1648114154350.png)]
前后端交互常用的通信加密方案:
客户端:
- 生成AES密钥,并保存AES密钥;
- 用AES密钥对请求传输数据进行加密;
- 使用RSA公钥对AES密钥加密,然后把值放到自定义的请求头;
- 向服务器发起请求;
服务端:
- 拿到自定义的请求头,用RSA私钥解密,得到AES密钥;
- 使用AES密钥对请求数据进行解密;
- 使用AES密钥对响应数据进行加密;
- 向客户端发送响应;
AES对称加密
AES加解密总共有以下这些
算法/模式/填充 字节加密后数据长度 不满16字节加密后长度
AES/CBC/NoPadding 16 不支持
AES/CBC/PKCS5Padding 32 16
AES/CBC/ISO10126Padding 32 16
AES/CFB/NoPadding 16 原始数据长度
AES/CFB/PKCS5Padding 32 16
AES/CFB/ISO10126Padding 32 16
AES/ECB/NoPadding 16 不支持
AES/ECB/PKCS5Padding 32 16
AES/ECB/ISO10126Padding 32 16
AES/OFB/NoPadding 16 原始数据长度
AES/OFB/PKCS5Padding 32 16
AES/OFB/ISO10126Padding 32 16
AES/PCBC/NoPadding 16 不支持
AES/PCBC/PKCS5Padding 32 16
AES/PCBC/ISO10126Padding 32 16
AES/ECB
- 不带模式和填充来获取AES算法的时候,其默认使用AES/ECB/PKCS5Padding(输入可以不是16字节,也不需要向量)
Cipher cipher = Cipher.getInstance("AES");
AES/ECB/PKCS5Padding
String content = "在线助手";// 生成密钥需要的密码值String key = "www.it399.com";/*** AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding** 不能使用填充向量* java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV*/System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");//128byte[] encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);//192encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_DEFAULT);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_DEFAULT);//256encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
AES/CBC
- 输入必须是16字节,不然报错 javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
- CBC模式必须提供初始向量IvParameterSpec,不然报错 java.security.InvalidKeyException: Parameters missing
content: 在线助手
key: www.it399.com111
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytesat com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1041)at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:1009)at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)at javax.crypto.Cipher.doFinal(Cipher.java:2165)at com.csy.spring.it399.controller.encode.aes.AESUtil.encrypt(AESUtil.java:80)at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:200)
java.security.InvalidKeyException: Parameters missingat com.sun.crypto.provider.CipherCore.init(CipherCore.java:470)at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:313)at javax.crypto.Cipher.implInit(Cipher.java:802)at javax.crypto.Cipher.chooseProvider(Cipher.java:864)at javax.crypto.Cipher.init(Cipher.java:1249)at javax.crypto.Cipher.init(Cipher.java:1186)at com.csy.spring.it399.controller.encode.aes.AESUtil.decrypt(AESUtil.java:117)at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:202)
encode: null
decode: null
初始化加密模式的时改成
Cipher cipher = Cipher.getInstance(“AES/CBC/NoPadding”);
java.security.InvalidKeyException: Parameters missing解决办法:
if (modeAndPadding.equals(EncodeType.AES_CBC_NoPadding)) {//指定一个初始化向量 (Initialization vector,IV), IV 必须是16位cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(getIV()));
} else {cipher.init(Cipher.ENCRYPT_MODE, keySpec);
}
AES/CBC/NoPadding, AES/CBC/PKCS5Padding, AES/CBC/ISO10126Padding
/*** 1.1 AES/CBC* AES/CBC/NoPadding* AES/CBC/PKCS5Padding* AES/CBC/ISO10126Padding*/
System.out.println("【1.1】AES_CBC_NoPadding模式");
content = "在线助手在线助手在线助手在线助手";
key = "www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
AES/CFB
-
需要向量,不然报如下错误
java.security.InvalidKeyException: Parameters missing
-
AES/CFB/NoPadding,AES/CFB/PKCS5Padding,AES/CFB/ISO10126Padding
/*** 1.2 AES/CFB* AES/CBC/NoPadding* AES/CBC/PKCS5Padding* AES/CBC/ISO10126Padding*/ System.out.println("【1.2】AES_CFB_NoPadding模式\n"); content = "在线助手"; // 生成密钥需要的密码值 key = "https://www.it399.com"; encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding); encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding); encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding); encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
AES/ECB
-
AES/ECB不要填充变量,不然会报如下错误
java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
AES/ECB/NoPadding,AES/ECB/PKCS5Padding,AES/ECB/ISO10126Padding
/*** 1.3 AES/ECB* AES/ECB/NoPadding* AES/ECB/PKCS5Padding* AES/ECB/ISO10126Padding*/System.out.println("【1.3】AES_ECB模式");content = "在线助手";// 生成密钥需要的密码值key = "https://www.it399.com";encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
完整代码
AESUtil .java
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/*** 在线助手|在线工具|在线生成|在线制作* https://www.it399.com/* 在线助手博客* https://www.it399.com/blog/index*/
public class AESUtil {public static final String CHARSET = "UTF-8";private static byte[] encryptOrDecrypt(int mode,byte[] byteContent, String key,byte[] iv, AESType type, String modeAndPadding) throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {KeyGenerator kgen = KeyGenerator.getInstance("AES");//此处解决mac,linux报错SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(key.getBytes());kgen.init(type.value, random);SecretKey secretKey = kgen.generateKey();byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, "AES");Cipher cipher = Cipher.getInstance(modeAndPadding);// 创建密码器if ( null !=iv ) {//指定一个初始化向量 (Initialization vector,IV), IV 必须是16位cipher.init(mode, keySpec, new IvParameterSpec(iv));} else {cipher.init(mode, keySpec);}byte[] result = cipher.doFinal(byteContent);return result;}public static void main(String[] args) throws Exception {
// System.out.println("【1】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
// // 需要加密的内容
// String content = "在线助手";
// // 生成密钥需要的密码值
// String key = "www.it399.com111";
// System.out.println("content: " + content + "\nkey: " + key);
// byte[] encodeByte;
// byte[] decodeByte;
// //默认方式 每次加密都不一样,但是秘钥是一样的,所以解密还是一样的
// // 内容加密后的值
// encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_128, EncodeType.AES_DEFAULT);
// String encodeStr = TypeConvert.bytesToHexString(encodeByte);
// // 被加密的内容解密后的值
// decodeByte = decrypt(encodeByte, key, AESType.AES_128, EncodeType.AES_DEFAULT);
// String decodeStr = new String(decodeByte,CHARSET);
// System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);
//
//
// System.out.println("【2】AES_CBC_NoPadding模式,输入必须是16*n字节,需要填充向量\n");
// // 内容加密后的值
// //待加密内容不足16*n位 报错javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
// //需要填充向量,不然报错java.security.InvalidKeyException: Parameters missing
// //得到加密后的内容先base64编码再解码再传给解码,不然直接转回乱码
// content = "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈";
// encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
// encodeStr = TypeConvert.bytesToHexString(encodeByte);
// decodeByte = decrypt(TypeConvert.hexStringToBytes(encodeStr), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
// decodeStr = new String(decodeByte,CHARSET);
// System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);String content = "在线助手";// 生成密钥需要的密码值String key = "www.it399.com";byte[] encrypt;/*** AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding*/
// System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
// //128
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
// //192
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
// //256
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
// /**
// * 1.1 AES/CBC (需要填充向量16*n)
// * AES/CBC/NoPadding
// * AES/CBC/PKCS5Padding
// * AES/CBC/ISO10126Padding
// */
// System.out.println("【1.1】AES_CBC_NoPadding模式,需要填充向量,待加密必须是16*n");
// content = "在线助手在线助手在线助手在线助手";
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
// /**
// * 1.2 AES/CFB
// * AES/CBC/NoPadding
// * AES/CBC/PKCS5Padding
// * AES/CBC/ISO10126Padding
// */
// System.out.println("【1.2】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "https://www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// /**
// * 1.2 AES/ECB
// * AES/ECB/NoPadding
// * AES/ECB/PKCS5Padding
// * AES/ECB/ISO10126Padding
// */
// System.out.println("【1.3】AES_ECB模式");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "https://www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);/*** 1.4 AES/OFB* AES/OFB/NoPadding* AES/OFB/PKCS5Padding* AES/OFB/ISO10126Padding*/System.out.println("【1.4】AES_OFB模式");content = "在线助手";// 生成密钥需要的密码值key = "https://www.it399.com";encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);/*** 1.5 AES/PCBC* AES/PCBC/NoPadding* AES/PCBC/PKCS5Padding* AES/PCBC/ISO10126Padding*/System.out.println("【1.5】AES_PCBC模式");content = "在线助手";// 生成密钥需要的密码值key = "https://www.it399.com";encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);//
// /**1.3 AES/CBC
// * AES_CBC_NoPadding模式(填充向量可选)
// */System.out.println("【1.3】AES_CBC_NoPadding模式");content = "在线助手在线助手在线助手在线助手";// 生成密钥需要的密码值key = "www.it399.com";encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);content = "在线助手";// 生成密钥需要的密码值key = "www.it399.com";encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
//
//
//
// /**
// * 2.1 AES/CFB 128/192/256位加解密
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.1】AES_CFB_NoPadding模式,需要填充向量\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
//
// /**
// * 2.2 AES/CFB
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.2】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//
// /**2.3 AES/CFB
// * AES_CFB_NoPadding模式(填充向量可选)
// */
// System.out.println("【2.3】AES_CFB_NoPadding模式\n");
// content = "在线助手";
// // 生成密钥需要的密码值
// key = "www.it399.com";
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
// encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);
// encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);}/**** @param isEncrypt* @param source* @param key* @param type* @param encodeType*/public static byte[] encryptOrdecrypt(boolean isEncrypt,byte[] source,String key,byte[] iv,AESType type,String encodeType) throws UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {if (isEncrypt){byte[] encodeByte = encryptOrDecrypt(Cipher.ENCRYPT_MODE,source,key,iv,type,encodeType);String encodeStr = TypeConvert.bytesToHexString(encodeByte);return encodeByte;}else{byte[] decodeByte = encryptOrDecrypt(Cipher.DECRYPT_MODE,source, key,iv,type, encodeType);String decodeStr = new String(decodeByte,CHARSET);return decodeByte;}}/*** 指定一个初始化向量 (Initialization vector,IV),IV 必须是16位*/public static final byte[] getIV() throws Exception {return "1234567812345678".getBytes(CHARSET);}
EncodeType
/*** 在线助手|在线工具|在线生成|在线制作* https://www.it399.com/* 在线助手博客* https://www.it399.com/blog/index*/
public class EncodeType {
// 算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度
// AES/CBC/NoPadding 16 不支持
// AES/CBC/PKCS5Padding 32 16
// AES/CBC/ISO10126Padding 32 16
// AES/CFB/NoPadding 16 原始数据长度
// AES/CFB/PKCS5Padding 32 16
// AES/CFB/ISO10126Padding 32 16
// AES/ECB/NoPadding 16 不支持
// AES/ECB/PKCS5Padding 32 16
// AES/ECB/ISO10126Padding 32 16
// AES/OFB/NoPadding 16 原始数据长度
// AES/OFB/PKCS5Padding 32 16
// AES/OFB/ISO10126Padding 32 16
// AES/PCBC/NoPadding 16 不支持
// AES/PCBC/PKCS5Padding 32 16
// AES/PCBC/ISO10126Padding 32 16//默认为 ECB/PKCS5Paddingpublic final static String AES_DEFAULT = "AES";public final static String AES_CBC_NoPadding = "AES/CBC/NoPadding";public final static String AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";public final static String AES_CBC_ISO10126Padding = "AES/CBC/ISO10126Padding";public final static String AES_CFB_NoPadding = "AES/CFB/NoPadding";public final static String AES_CFB_PKCS5Padding = "AES/CFB/PKCS5Padding";public final static String AES_CFB_ISO10126Padding = "AES/CFB/ISO10126Padding";public final static String AES_ECB_NoPadding = "AES/ECB/NoPadding";public final static String AES_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";public final static String AES_ECB_ISO10126Padding = "AES/ECB/ISO10126Padding";public final static String AES_OFB_NoPadding = "AES/OFB/NoPadding";public final static String AES_OFB_PKCS5Padding = "AES/OFB/PKCS5Padding";public final static String AES_OFB_ISO10126Padding = "AES/OFB/ISO10126Padding";public final static String AES_PCBC_NoPadding = "AES/PCBC/NoPadding";public final static String AES_PCBC_PKCS5Padding = "AES/PCBC/PKCS5Padding";public final static String AES_PCBC_ISO10126Padding = "AES/PCBC/ISO10126Padding";
}
另附代码
package net.trueland.employee.common;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;import com.alibaba.fastjson.JSONObject;public class SecurityUtils {public static final String ALGORITHM_AES = "AES";public static final String CHARSET_UTF8 = "UTF-8";/*** 参数加签* @param json 参数,仅支持json对象* @param key 密钥* @return 密文*/public static String signParam(String json, String key) throws Exception {if (StringUtils.isBlank(json)) {return StringUtils.EMPTY;}if (StringUtils.isBlank(key)) {throw new Exception("param add sign error: no key");}StringBuffer stringBuffer = new StringBuffer(key);JSONObject jsonObject = JSONObject.parseObject(json);List<String> keyList = new ArrayList<String>(jsonObject.keySet());keyList.remove("sign");Collections.sort(keyList);for (String s : keyList) {Object o = jsonObject.get(s);if (o == null) {o = "";}stringBuffer.append(s);stringBuffer.append(o);}return stringBuffer.toString();}/*** md5 加密* @param str 明文* @return*/public static String encryptMD5(String str) {MessageDigest md = null;try {md = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {// TODO 异常处理}md.update(str.getBytes());byte[] b = md.digest();StringBuilder buf = new StringBuilder();byte[] var5 = b;int var6 = b.length;for (int var7 = 0; var7 < var6; ++var7) {byte aB = var5[var7];int i = aB;if (aB < 0) {i = aB + 256;}if (i < 16) {buf.append("0");}buf.append(Integer.toHexString(i));}return buf.toString();}// ------------------------------------------AES/ECB/PKCS5Padding加解密, AES默认的加密方式--------------------------------------------------/*** 加密速度快* 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV* @param plaintext 明文* @param key 密钥 不强制位数* @return 密文*/public static String encrypt(String plaintext, String key) throws Exception {return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, null, "AES/ECB/PKCS5Padding");}/*** 加密速度快* 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV* @param ciphertext 密文* @param key 密钥 不强制位数* @return 明文*/public static String decrypt(String ciphertext, String key) throws Exception {return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, null, "AES/ECB/PKCS5Padding");}// ------------------------------------------AES/CBC/PKCS5Padding 加解密--------------------------------------------------/*** 安全性高,加密速度慢* CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing* @param plaintext 明文* @param key 密钥,不强制位数* @param offset 偏移量,提高安全性,强制16位* @return 密文*/public static String encrypt(String plaintext, String key, String offset) throws Exception {return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");}/*** 安全性高,加密速度慢* CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing* @param ciphertext 密文* @param key 密钥,不强制位数* @param offset 偏移量,提高安全性,强制16位* @return 明文*/public static String decrypt(String ciphertext, String key, String offset) throws Exception {return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");}/*** 加密或解密* @param mode 加密1 解密2* @param content 明文或密文* @param key 密钥* @param iv 向量* @param modeAndPadding 加密类型和填充类型* @return* @throws Exception*/private static String encryptOrDecrypt(int mode, String content, String key, byte[] iv, String modeAndPadding) throws Exception {byte[] byteContent = Cipher.ENCRYPT_MODE == mode ? content.getBytes(CHARSET_UTF8) : Base64.decodeBase64(content);// 密钥生成器KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);// 随机数,不可以随时间随机,否则mac,linux报错SecureRandom random = SecureRandom.getInstance("SHA1PRNG");// 设置随机种子random.setSeed(key.getBytes(CHARSET_UTF8));// 初始化密钥生成器keyGenerator.init(128, random);// 生成密钥SecretKey secretKey = keyGenerator.generateKey();// 生成AES专用密钥SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);// 创建加/解密器Cipher cipher = Cipher.getInstance(modeAndPadding);// 初始化加/解密器if (null != iv){// 指定向量,提高安全性cipher.init(mode,secretKeySpec,new IvParameterSpec(iv));}else {cipher.init(mode, secretKeySpec);}// 加密/解密byte[] result = cipher.doFinal(byteContent);return Cipher.ENCRYPT_MODE == mode ? Base64.encodeBase64String(result) : new String(result);}/*** 随机生成指定长度的密钥* @param length*/public static String randomKey(int length){return RandomStringUtils.randomAlphanumeric(length);}
}
RSA非对称加密
public class RSAEncrypt {private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥public static void main(String[] args) throws Exception {//生成公钥和私钥genKeyPair();//加密字符串String message = "df723820";System.out.println("随机生成的公钥为:" + keyMap.get(0));System.out.println("随机生成的私钥为:" + keyMap.get(1));String messageEn = encrypt(message,keyMap.get(0));System.out.println(message + "\t加密后的字符串为:" + messageEn);String messageDe = decrypt(messageEn,keyMap.get(1));System.out.println("还原后的字符串为:" + messageDe);}/** * 随机生成密钥对 * @throws NoSuchAlgorithmException */ public static void genKeyPair() throws NoSuchAlgorithmException { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); // 初始化密钥对生成器,密钥大小为96-1024位 keyPairGen.initialize(1024,new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥 String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); // 得到私钥字符串 String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded()))); // 将公钥和私钥保存到MapkeyMap.put(0,publicKeyString); //0表示公钥keyMap.put(1,privateKeyString); //1表示私钥} /** * RSA公钥加密 * * @param str * 加密字符串* @param publicKey * 公钥 * @return 密文 * @throws Exception * 加密过程中的异常信息 */ public static String encrypt( String str, String publicKey ) throws Exception{//base64编码的公钥byte[] decoded = Base64.decodeBase64(publicKey);RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));//RSA加密Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, pubKey);String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));return outStr;}/** * RSA私钥解密* * @param str * 加密字符串* @param privateKey * 私钥 * @return 铭文* @throws Exception * 解密过程中的异常信息 */ public static String decrypt(String str, String privateKey) throws Exception{//64位解码加密后的字符串byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));//base64编码的私钥byte[] decoded = Base64.decodeBase64(privateKey); RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); //RSA解密Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, priKey);String outStr = new String(cipher.doFinal(inputByte));return outStr;}}
相关文章:

全后端交互数据加密
前后端交互 通信请求使用https对请求参数进行签名,防止数据篡改对请求参数以及响应数据进行加解密app中使用ssl pinning防止抓包操作 https协议 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78n9M2PH-1677252127361)(安全.assets/ht…...

稀疏特征和密集特征
在机器学习中,特征是指对象、人或现象的可测量和可量化的属性或特征。特征可以大致分为两类:稀疏特征和密集特征。 稀疏特征 稀疏特征是那些在数据集中不连续出现的特征,并且大多数值为零。稀疏特征的示例包括文本文档中特定单词的存在或不存…...

Linux网络TCP sticky分析工具
1 TCP粘包 - TCP_NODELAY TCP粘包(sticky)的表现是TCP nagle算法将应用层发送的多个包进行合并后,再发送,很容易出现burst导致bcm89230丢包。由于OABR不支持流控,所以需要使用Linux tc对对应的TCP port进行流量整形。 …...

华为OD机试题,用 Java 解【DNA 序列】问题
最近更新的博客 华为OD机试 - 猴子爬山 | 机试题算法思路 【2023】华为OD机试 - 分糖果(Java) | 机试题算法思路 【2023】华为OD机试 - 非严格递增连续数字序列 | 机试题算法思路 【2023】华为OD机试 - 消消乐游戏(Java) | 机试题算法思路 【2023】华为OD机试 - 组成最大数…...

python的所有知识点+代码+注释,不看就亏死了
目录 简介 特点 搭建开发环境 版本 hello world 注释 文件类型 变量 常量 数据类型 运算符和表达式 控制语句 数组相关 函数相关 字符串相关 文件处理 对象和类,注:不是那个对象!!!!&…...

读懂分布式事务
一、概述 1.1 什么是分布式事务 事务我们都很熟悉,事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成这组操作的各个单元,要么全部成功,要么全部失败。 事务有四大特性: Atomic…...

多目标粒子群算法求解帕累托前沿Pareto,Pareto的原理,测试函数100种求解之21
目录 背影 parte前沿的定义 注意事项 基于多目标粒子群的帕累托前沿求解 主要参数 MATLAB代码 效果图 结果分析 展望 背影 在目标优化过程种,很多时候都两个或者多个目标,并且目标函数不能同时达到最优,鱼与熊掌不可兼得,这个时候可以通过求解帕累托前沿,通过帕累托前沿…...

数组:二分查找、移除数组等经典数组题
二分查找:相关题目链接:https://leetcode.cn/problems/binary-search/题目重现:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值…...

负责任动物纤维标准RAF
【负责任动物纤维标准RAF】RAF-Responsible Animal Fiber, 中文翻译为负责任动物纤维标准。RAF标准包含了三个子标准,即RWS(责任羊毛标准)、RMS(责任马海毛标准)和RAS(责任羊驼毛标准)。RWS&…...

storybook使用info插件报错
报错内容: RangeErrorMaximum call stack size exceededCall StackprettyPrintvendors-node_modules_pmmmwh_react-refresh-webpack-plugin_lib_runtime_RefreshUtils_js-node_mod-4ff2dd.iframe.bundle.js:160:27undefinedvendors-node_modules_pmmmwh_react-refresh-webpack-…...

【每日一题Day129】LC1247交换字符使得字符串相同 | 贪心
交换字符使得字符串相同【LC1247】 有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 "x" 和 "y",你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候,你都可以在两个字符串中各选一个字…...

性能优化之node中间件耗时
背景 中间件在node框架中是很基本的套件,使用不当很容易对页面性能造成影响。除了node服务端外,前端做的SSR项目也要特别重视这块 哪些场景会造成中间件耗时特别严重? 罪魁祸首是:await阻塞 举个例子: 1.如何得到 …...

3-1 图文并茂说明raid0,raid1, raid10, raid01, raid5等原理
文章目录简介RAID类型RAID0RAID1RAID5RAID6RAID10RAID01RAID对比图简介 一、RAID 是什么? RAID ( Redundant Array of Independent Disks )即独立磁盘冗余阵列,简称为「磁盘阵列」,其实就是用多个独立的磁盘组成在一起…...

西北工业大学大学物理(I)下2019-2020选填考题解析
单选题12个,24分。1量子数考查前三个量子数由薛定谔方程决定,最后一个关于自旋的由狄拉克方程决定由这些量子数可以给出原子的壳层结构。考试其实考的不深,记住这个表就够了。2 书上18、19章量子物理的著名实验:光电效应ÿ…...

自动化测试selenium
目录 一、为什么引入自动化测试? 二、为什么选择selenium作为自动化测试工具? 三、环境部署 四、什么是驱动?驱动的工作原理? 五、selenium的基础语法 元素定位 元素操作 点击元素 模拟键盘输入 清除对象输入的文本…...

熟悉GC常用算法,熟悉常见垃圾收集器,具有实际JVM调优实战经验
程序的栈和堆 栈先进后出,且里面的数据自动释放, 堆内的空间则需要手动释放 java python go 只管创建,不用像c,c需要手动释放空间, 因为他们都会开一个进程GC(Garbage Collector),由垃圾回收…...

常量和变量——“Python”
各位CSDN的uu们你们好呀,今天,小雅兰的内容是Python的一些基础语法噢,会讲解一些常量和变量的知识点,那么,现在就让我们进入Python的世界吧 常量和表达式 变量和类型 变量是什么 变量的语法 变量的类型 常量和表达式 …...

《蓝桥杯每日一题》KMP算法·AcWing 141. 周期
1.题目描述一个字符串的前缀是从第一个字符开始的连续若干个字符,例如 abaab 共有 55 个前缀,分别是 a,ab,aba,abaa,abaab。我们希望知道一个 N 位字符串 S 的前缀是否具有循环节。换言之,对于每…...

URL介绍
前言Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL(Uniform Resource Locator, 统一资源定位器)。它是www的统一资源定位标志,简单地说URL就是web地址,俗称“网址”。一、URL概念URL是对互联网上得到…...

学习 Python 之 Pygame 开发魂斗罗(一)
学习 Python 之 Pygame 开发魂斗罗(一)Pygame回忆Pygame1. 使用pygame创建窗口2. 设置窗口背景颜色3. 获取窗口中的事件4. 在窗口中展示图片(1). pygame中的直角坐标系(2). 展示图片(3). 给部分区域设置颜色5. 在窗口中显示文字6. 播放音乐7. 图片翻转与…...

ARM uboot 源码分析8 - uboot的环境变量
一、uboot 的环境变量基础 1、环境变量的作用 (1) 让我们可以不用修改 uboot 的源代码,而是通过修改环境变量,来影响 uboot 运行时的一些数据和特性。譬如说,通过修改 bootdelay 环境变量,就可以更改系统开机自动启动时倒数的秒…...

【蓝牙mesh】Network协议层介绍
【蓝牙mesh】Network协议层介绍 Network层简介 上一章节我们讲解了蓝牙Mesh中Lower层的功能和数据格式。 Lower层的数据往下传输就到了网络层(Network Layer)。网络层定义了收到Lower层的数据后,如何对其进行判断、封装、加密、认证…...

基于遗传算法的配电网故障定位(Matlab代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...

Leetcode.1247 交换字符使得字符串相同
题目链接 Leetcode.1247 交换字符使得字符串相同 Rating : 1597 题目描述 有两个长度相同的字符串 s1和 s2,且它们其中 只含有 字符 "x"和 "y",你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时…...

python语音识别whisper
一、背景 最近想提取一些视频的字幕,语音文案,研究了一波 二、whisper语音识别 Whisper 是一种通用的语音识别模型。它在不同音频的大型数据集上进行训练,也是一个多任务模型,可以执行多语言语音识别以及语音翻译和语言识别。 …...

Prometheus -- 浅谈Exporter
Prometheus系统 – Exporter原理 为什么我们需要Exporter? 广义上讲所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为target,如下所示,Prometheus通过轮询的方式定期从这些target中获取样本…...

如何确定RocketMQ中消费者的线程大小
背景 随着物联网行业的发展、智能设备数量越来越多,随着设备活跃量过大,常常存在一些高并发的请求,形成了流量尖峰,过多的请求会压垮服务器,影响其他服务运行。因此,为了保护云端服务,需要对请求…...

OpenAPI SDK组件之Spring Aop源码拓展
Spring Aop 看这个分享的应该都用过Spring Aop,这里就不再过多介绍了它是什么了。 我抽取了Spring Aop的部分源码,通过它实现请求参数可变拦截,同时apisdk离开Spring框架,仍然可以正常运行。 讲拦截也好,通知也罢&a…...

蓝桥杯C/C++VIP试题每日一练之龟兔赛跑预测
💛作者主页:静Yu 🧡简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者 💛社区地址:前端知识交流社区 🧡博主的个人博客:静Yu的个人博客…...

为你的Vue2.x老项目安装Vite发动机吧
天下苦webpack久矣,相信作为前端开发者一定经历过在项目迭代时间较长的时候经历漫长等待的这一过程,每一次保存都会浪费掉大量时间,这是webpack这种机制所带来的问题。 于是,尤大为我们带来了新一代前端构建工具:vite…...