一、问题描述
微信小程序获取手机号,官方通常会返回密文数据给我们,此时就需要我们自行解密数据。在揭秘的数据过程中会发现,第一次授权获取手机号会出现错误,再次获取的时候就能够正常获取。
错误信息一般分两种:
密文后端解密的javax.crypto.BadPaddingException: pad block corrupted(后端语言为java)错误;
密文前端解密的Illegal Buffer at WXBizDataCrypt.define.push.WXBizDataCrypt.decryptData错误。
二、错误原因
在回调里面又调用一次wx.login()导致登录状态被刷新,此时用code换取的sessionKey,不是的当时encryptedData对应的sessionKey,这个时候就导致了解密失败。
例如:
由于**@getphonenumber是获取用户手机号回调方法,然后又在回调中调用了一次login()**,导致出现上述问题。
三、解决方法
3.1 不推荐方法
当出现上述问题的时候,可以弹出提示,引导用户再点击一次授权,出现两次错误的几率还是不高的,业务允许的话,可以这么干。
文章来源:https://www.toymoban.com/news/detail-611727.html
3.2 正确方法
试想一下,出现问题的原因是啥,当然是在回调里面又重新login()了一下,那么能不能把login()放在回调外面。
也就是先调用login()方法获取code(不要在@getphonenumbe里面调用login),然后在获取sessionKey,解密数据。
文章来源地址https://www.toymoban.com/news/detail-611727.html
四、附录
4.1 后端解密方法
import com.alibaba.fastjson.JSONObject;
WXBizDataCryptUtil util = new WXBizDataCryptUtil(properties.getAppId(), dto.getSessionKey());
JSONObject data = util.decrypt(dto.getEncryptedData(), dto.getIv());
import com.alibaba.fastjson.JSONObject;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.Security;
import java.util.Base64;
/**
* 微信数据解密工具
*
* @date 2023-06-08 16:51:26
*/
public class WXBizDataCryptUtil {
public static JSONObject getMoreInfoFromEncryptedData(String appId, String sessionKey, String encryptedData, String iv) {
WXBizDataCryptUtil pc = new WXBizDataCryptUtil(appId, sessionKey);
JSONObject decrypt = pc.decrypt(encryptedData, iv);
return decrypt;
}
private String appId;
private String sessionKey;
public WXBizDataCryptUtil(String appId, String sessionKey) {
this.appId = appId;
this.sessionKey = sessionKey;
}
/**
* 解密成json
*
* @param encryptedData
* @param iv
* @return
*/
public JSONObject decrypt(String encryptedData, String iv) {
byte[] encryptedDataDecode = Base64.getDecoder().decode(encryptedData);
byte[] sessionKeyDecode = Base64.getDecoder().decode(this.sessionKey);
byte[] ivDecode = Base64.getDecoder().decode(iv);
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] decodeData = decode(encryptedDataDecode, sessionKeyDecode, ivDecode);
String stringData = new String(decodeData);
JSONObject jsonObject = JSONObject.parseObject(stringData);
return jsonObject;
}
/**
* 解密算法 AES-128-CBC
* 填充模式 PKCS#7
*
* @param encryptedDataDecode 目标密文
* @return
* @throws Exception
*/
private byte[] decode(byte[] encryptedDataDecode, byte[] sessionKeyDecode, byte[] iv) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(sessionKeyDecode, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIv(iv));// 初始化
byte[] result = cipher.doFinal(encryptedDataDecode);
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 处理iv
*
* @param iv
* @return
* @throws Exception
*/
private AlgorithmParameters generateIv(byte[] iv) throws Exception {
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
4.2 前端解密
getPhoneNumber(e) {
if (e.detail.errMsg === 'getPhoneNumber:ok') {
getOpenId({
code: this.wxCode
})
.then(openIdRes => {
if (!openIdRes.success) {
this.$refs.page.closeLoading()
showErrorToast(this.$refs.uToast, {
position: 'top',
message: openIdRes.message
})
return
}
const data = openIdRes.data
const wxCryto = new WXBizDataCrypt(data.appId, data.sessionKey)
const encryptData = wxCryto.decryptData(e.detail.encryptedData, e.detail.iv)
console.log('解密结果', encryptData)
})
.catch(err => {
console.log(err)
this.$refs.page.closeLoading()
showErrorToast(this.$refs.uToast, {
position: 'top',
message: '获取微信参数异常, 请重试'
})
})
}
}
var crypto = require('crypto')
function WXBizDataCrypt(appId, sessionKey) {
this.appId = appId
this.sessionKey = sessionKey
}
WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
// base64 decode
var sessionKey = new Buffer(this.sessionKey, 'base64')
encryptedData = new Buffer(encryptedData, 'base64')
iv = new Buffer(iv, 'base64')
try {
// 解密
var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
// 设置自动 padding 为 true,删除填充补位
decipher.setAutoPadding(true)
var decoded = decipher.update(encryptedData, 'binary', 'utf8')
decoded += decipher.final('utf8')
decoded = JSON.parse(decoded)
} catch (err) {
throw new Error('Illegal Buffer')
}
if (decoded.watermark.appid !== this.appId) {
throw new Error('Illegal Buffer')
}
return decoded
}
module.exports = WXBizDataCrypt
到了这里,关于微信小程序中获取用户手机号密文数据解密报错问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!