吐血記錄微信小程序授權獲取Unionid及linux下使用bouncycastle解密用戶數據 遇到的坑
背景
公司小程序上線了,發現系統無法拿到一些用戶的UniondID。但是上線前的測試一切都是正常的。
坑1
經排查,發現一些用戶通過下面的接口無法得到unionid
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
閱讀https://developers.weixin.qq.com/miniprogram/dev/api/uinionID.html 得知,從未在關聯公眾號或小程序進行授權過的用戶,是不會直接返回unionid的。要拿到這些用戶的unionid需要以下3個數據
1.https://api.weixin.qq.com/sns/jscode2session返回的session_key
2. wx.getUserInfo且用戶同意後返回的encryptedData和iv
使用以下代碼可以解密出用戶的信息
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.NoSuchProviderException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AES {
public static boolean initialized = false;
public static void main(String[] args) throws InvalidAlgorithmParameterException, UnsupportedEncodingException {
String encryptedData = "";
String iv = "";
String sessionKey = "";
byte[] resultByte = AES.decrypt(Base64.decodeBase64(encryptedData),
Base64.decodeBase64(sessionKey),
Base64.decodeBase64(iv));
System.out.println(new String(resultByte,"utf-8"));
}
/**
* AES解密
*
* @param content 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void initialize() {
if (initialized) return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
//生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
坑2,真正吐血的地方
使用以上的方法在我本機上面進行測試是沒問題的,但是將項目部署上Linux上之後又出了一個問題
解密的時候拋異常:
java.security.NoSuchAlgorithmException - Cannot find any provider supporting AES/CBC/PKCS7Padding
我回頭看代碼,要實現在java端用PKCS7Padding填充,需要用到bouncycastle組件來實現,解密代碼中確實也設置了。且本機也是可以解密的,本機和linux上的jdk均是官網下載的1.8版本,為什麽Linux上就不行呢
//使用BouncyCastleProvider組件填充
Security.addProvider(new BouncyCastleProvider());
maven中也引用了bouncycastle
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.59</version>
</dependency>
排除代碼問題的話很明顯是環境問題了,linux上使用Security.addProvider(new BouncyCastleProvider()); 不起效果。。。
那沒辦法了,只能手動改jre。步驟如下
1.把bcprov-jdk15on-1.59.jar 復制到jre目錄中的/lib/ext
2.編輯/lib/security/java.security
....
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
#在此加上這句代碼
security.provider.x=org.bouncycastle.jce.provider.BouncyCastleProvider
.....
3.重啟tomcat,解密成功了。。。
附一份檢測是否支持bouncycastle的代碼。方法:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import java.security.Security;
public class TestB {
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
System.out.println("Attemptingto get a Cipher and encrypt...");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
System.out.println("OK");
}
}
如果想用純Js解密也是可以的,這裏有一篇文章:https://www.cnblogs.com/cai-rd/p/6816849.html
吐血記錄微信小程序授權獲取Unionid及linux下使用bouncycastle解密用戶數據 遇到的坑