这个问题解决了好久,在网上查找各种资料因为涉及到加密算法(不是很了解),所以进度很慢 还有就是小程序的坑是在时太多了,当然和自己不细心阅读文档也有关系(但是个人表示 一些文档真的都不清楚要表达的意思)特此记录。
首先声明下本文本着学习的态度与大家交流,如果有写的不好理解不够的地方欢迎大家指正,不喜勿喷。
在此说一下我的需求,很简单获取微信绑定的手机号码 相信很多人都是为了获取这个的。
那当我们查看小程序给出的文档时我们会看到它为我们提供了一个简便的获取手机号码的方式;
如果你是个人号就不用费这个力气了,洗洗睡吧
这就是调用的返回结果,当然你可以试一下 怎么使用文档中有直接copy即可;
但是不认为如果是个人号小程序不提供获取手机号码的方法,于是继续百度上代码;
wxml
js
这是完整的代码,解释下为什么要在登陆回调中去写,通过login回调获取的code是有时效的 每次请求他都会刷新,并且只能使用一次,在解密时需要这个code 并且要与最新的保持一致所以在调用login后在进行解密,还有一种方法(我还没试)可以先判断是否登陆状态,true:将需要的code存起来; false:就调用login;
onGotUserInfo(e) {
//获取用户信息的新方法,老方法以后将不再支持
console.log(e.detail)
let encryptedData = e.detail.encryptedData;
let iv = e.detail.iv;
wx.login({
success: function (res) {
if(res.code){
wx.request({
method: "POST",
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
url: url,
data: {
json:"{\"code\":\""+res.code+"\"}",
"method":"login"
},success: function (result) {
wx.request({
method: "POST",
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
url: url,
data: {
"json":"{\"encryptedData\":\""+encryptedData+"\",\"iv\":\""+iv+"\",\"session_key\":\""+result.data.session_key+"\"}",
"method":"getDecrypt"
},success: res=> {
//debugger;
console.log("解密返回数据:"+res.data)
wx.hideLoading()
}, fail(){
//这是失败函数
}
})
}, fail(){
//这是失败函数
}
})
}else{
console.log("登陆失败!")
}
}
})
}
解密算法文档中有写,但是不知道为什么 实力文档就是没有java示例,只能自己查资料摸索,看文档理解大概含义,首先用base64解密,后在使用AES算法解密 搞定,至于参数哪来的 看上面的代码即可;
java
相信这才是大家关心的代码,直接上具体实现
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;
public class MyBase64 {
//算法名
private static final String KEY_ALGORITHM = "AES";
//填充
private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding";
//密钥格式
private static Key key;
private static Cipher cipher;
//将传递过来的数据 用base64先行解密
public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) {
return new String(
decryptOfDiyIV(
Base64.decode(encryptDataB64),
Base64.decode(sessionKeyB64),
Base64.decode(ivB64)
)
);
}
private static void init(byte[] keyBytes) {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
int base = 16;
if (keyBytes.length % base != 0) {
int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
keyBytes = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
// 转化成JAVA的密钥格式
key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
try {
// 初始化cipher
cipher = Cipher.getInstance(ALGORITHM_STR, "BC");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解密方法
* @param encryptedData 要解密的字符串
* @param keyBytes 解密密钥
* @param ivs 自定义对称解密算法初始向量 iv
* @return 解密后的字节数组
*/
private static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes, byte[] ivs) {
byte[] encryptedText = null;
init(keyBytes);
try {
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
encryptedText = cipher.doFinal(encryptedData);
} catch (Exception e) {
e.printStackTrace();
}
return encryptedText;
}
}
返回数据json格式化后
并没有我所需要的手机号码(本文的标题就是解密数据,而不是获取手机号码),至于如何获取还在找方法 如果找到还会继续和大家分享!