首先Java可以定义一个全局处理的一个类,通过实现RequestBodyAdvice
来进行统一接口请求参数处理。实现RequestBodyAdvice
后重写一个方法beforeBodyRead
。
MethodParameter
获取请求的方法,这里可以设置一些白名单等,直接放行之类的操作,主要的一行代码如下:MethodParameter.getMethod().getName())
HttpInputMessage
获取到body的请求参数。String encryptedText = IOUtils.toString(inputMessage.getBody(), Charset.defaultCharset());
获取到加密的字符串之后就可以进行解密操作了。我这里首先在全局
调用了一个工具类RSATools
,在全局处理的类中就一行代码
encryptedText = RSATools.decrypt(encryptedText, privateKey);
首先解释一下privateKey
就是一个私钥,这是你自己生成的RSA加密字符串。
接下来给大家看一下RSATools
工具类(有些敏感信息进行了脱敏):这个类大家可以简单扫一眼即可,主要的解密方法我进行了抽取,在下面。
public class RSATools {
public static final String SIGN_ALGORITHMS = "自己的签名";
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 245;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 256;
private static final String PRIVATEKEY = "自己的私钥";
/**
* 签名
*
* @param content
* @param privateKey
* @return
*/
public static String sign(String content, String privateKey) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Tools.decode2Byte(privateKey));
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update(content.getBytes(DEFAULT_CHARSET));
byte[] signed = signature.sign();
return Base64Tools.encode2String(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 验签
*
* @param content
* @param sign
* @param publicKey
* @return
*/
public static boolean verify(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64Tools.decode2Byte(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
signature.initVerify(pubKey);
signature.update(content.getBytes(DEFAULT_CHARSET));
return signature.verify(Base64Tools.decode2Byte(sign));
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes = Base64Tools.decode2Byte(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes = Base64Tools.decode2Byte(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
public static String getKeyString(Key key) throws Exception {
byte[] keyBytes = key.getEncoded();
return Base64Tools.encode2String(keyBytes);
}
public static <T> String getSignatureContent(Map<String, T> params) {
if (params == null) {
return null;
}
StringBuffer content = new StringBuffer();
@SuppressWarnings({ "rawtypes", "unchecked" })
List<String> keys = new ArrayList(params.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++) {
String key = (String) keys.get(i);
if (params.get(key) != null) {
String value = String.valueOf(params.get(key));
content.append((i == 0 ? "" : "&") + key + "=" + value);
}
}
return content.toString();
}
@SuppressWarnings("unchecked")
public static String getListSignatureContent(@SuppressWarnings("rawtypes") List<Map> mapList) {
if (mapList == null) {
return null;
}
@SuppressWarnings({ "rawtypes" })
List<String> listStr = new ArrayList();
for (Map<String, Object> map : mapList) {
listStr.add(getSignatureContent(map));
}
Collections.sort(listStr);
return listStr.toString();
}
/**
* 分段加密
*/
public static final String KEY_ALGORITHM = "RSA";
public static String encrpyt(String content, String publicKeyStr) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(1, getPublicKey(publicKeyStr));
byte[] bytes = content.getBytes(DEFAULT_CHARSET);
int inputLen = bytes.length;
int offSet = 0;
byte[] cache;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return Base64Tools.encode2String(encryptedData);
}
/**
* 分段解密
*
* @param content
* @param privateKeyStr
* @return
* @throws Exception
*/
public static String decrypt(String content, String privateKeyStr) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
byte[] bytes = Base64Tools.decode2Byte(content);
int inputLen = bytes.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
//System.out.println("第"+i+"次"+(inputLen - offSet >= MAX_DECRYPT_BLOCK) + " -- " + inputLen+" -- "+offSet+" -- "+MAX_DECRYPT_BLOCK+" -- "+(inputLen - offSet));
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
offSet += MAX_DECRYPT_BLOCK;
} else {
cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
offSet += (inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
}
byte[] decryptedData = out.toByteArray();
out.close();
String result = new String(decryptedData);
result=result.replaceAll("<","《");
result=result.replaceAll(">","》");
result=result.replaceAll("\\(","(");
result=result.replaceAll("\\)",")");
result=result.replaceAll("!","!");
result=result.replaceAll("`","·");
result=result.replaceAll("\\n","n");
return result;
}
public static String decryptTwoBarCode(String content) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(2, getPrivateKey(PRIVATEKEY));
byte[] bytes = Base64Tools.decode2Byte(content);
int inputLen = bytes.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(bytes, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
String result = new String(decryptedData);
result=result.replaceAll("<","《");
result=result.replaceAll(">","》");
result=result.replaceAll("\\(","(");
result=result.replaceAll("\\)",")");
result=result.replaceAll("!","!");
result=result.replaceAll("`","·");
return result;
}
}
解密、分段解密的主要方法:
/**
* 分段解密
*
* @param content
* @param privateKeyStr
* @return
* @throws Exception
*/
public static String decrypt(String content, String privateKeyStr) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
byte[] bytes = Base64Tools.decode2Byte(content);
int inputLen = bytes.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
//System.out.println("第"+i+"次"+(inputLen - offSet >= MAX_DECRYPT_BLOCK) + " -- " + inputLen+" -- "+offSet+" -- "+MAX_DECRYPT_BLOCK+" -- "+(inputLen - offSet));
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
offSet += MAX_DECRYPT_BLOCK;
} else {
cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
offSet += (inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
}
byte[] decryptedData = out.toByteArray();
out.close();
String result = new String(decryptedData);
result=result.replaceAll("<","《");
result=result.replaceAll(">","》");
result=result.replaceAll("\\(","(");
result=result.replaceAll("\\)",")");
result=result.replaceAll("!","!");
result=result.replaceAll("`","·");
result=result.replaceAll("\\n","n");
return result;
}
这个就是Java后台的主要方法了。大致说一下我的解密过程: 总结:
首先我在全局处理类中实现了
RequestBodyAdvice
接口,并在重写的beforeBodyRead
方法中进行了获取方法、以及方法参数的操作、并且要是方法不在白名单中我就进行了一个解密。调用了工具类RSATools
的decrypt方法,传入了获取到的需要解密的字符串,以及私钥。这就是大致的JavaRSA解密的思路,相关代码上面已经站出来了。
接下来主要说一下我前台怎么传输的吧。
主要代码:
let src = JSON.stringify(config.data);
CryptoJS.enc.Utf8.parse(src);
let encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
//公钥加密
var encrypted = encrypt.encryptLong(src);
config.data = encrypted;
这里我使用了jsencrypt.min.js
工具类,
并且重写了(或者说新增)它里面的加密方法。
这里说一下为什么要修改这个工具类的加密方法。因为在实际生产环境中,你并不能确定你的参数长度具体有多长。网上相关的案例也都是简单的使用这个工具类jsencrypt.min.js
自带的加密方法。这个方法使用过程中如果要是简单的、较短的数据参数的一个提交是没有问题的。但是如果要是数据参数过长的话,后面是解析不出来的。所以我在这里进行了一个修改增强。
主要修改方式你在拦截器的js类中编写即可。
js增强代码:
JSEncrypt.prototype.encryptLong = function (string) {
var k = this.getKey();
try {
var ct = "";
//RSA每次加密117bytes,需要辅助方法判断字符串截取位置
//1.获取字符串截取点
var bytes = new Array();
bytes.push(0);
var byteNo = 0;
var len, c;
len = string.length;
var temp = 0;
for (var i = 0; i < len; i++) {
c = string.charCodeAt(i);
if (c >= 0x010000 && c <= 0x10FFFF) { //特殊字符,如Ř,Ţ
byteNo += 4;
} else if (c >= 0x000800 && c <= 0x00FFFF) { //中文以及标点符号
byteNo += 3;
} else if (c >= 0x000080 && c <= 0x0007FF) { //特殊字符,如È,Ò
byteNo += 2;
} else { // 英文以及标点符号
byteNo += 1;
}
if ((byteNo % 117) >= 114 || (byteNo % 117) == 0) {
if (byteNo - temp >= 114) {
bytes.push(i);
temp = byteNo;
}
}
}
//2.截取字符串并分段加密
if (bytes.length > 1) {
for (var i = 0; i < bytes.length - 1; i++) {
var str;
if (i == 0) {
str = string.substring(0, bytes[i + 1] + 1);
} else {
str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
}
var t1 = k.encrypt(str);
ct += t1;
}
;
if (bytes[bytes.length - 1] != string.length - 1) {
var lastStr = string.substring(bytes[bytes.length - 1] + 1);
ct += k.encrypt(lastStr);
}
return hex2b64(ct);
}
var t = k.encrypt(string);
var y = hex2b64(t);
return y;
} catch (ex) {
console.log(ex);
return false;
}
};
function hex2b64(h) {
var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var b64padchar="=";
var i;
var c;
var ret = "";
for(i = 0; i+3 <= h.length; i+=3) {
c = parseInt(h.substring(i,i+3),16);
ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
}
if(i+1 == h.length) {
c = parseInt(h.substring(i,i+1),16);
ret += b64map.charAt(c << 2);
}
else if(i+2 == h.length) {
c = parseInt(h.substring(i,i+2),16);
ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
}
while((ret.length & 3) > 0) ret += b64padchar;
return ret;
}
最后给大家分享一下相关博主的文章,比较有用的,避免踩坑吧。 https://www.jianshu.com/p/621d8f7e2b44 https://blog.csdn.net/qq_37314372/article/details/104520559
前端的加密解密案例: