我使用了两种方式,分享出来,新人练手,不喜勿喷。一种是通过js方式直接解析,一种是传输给后台通过java进行解析。关键参数三个encryptedData,iv,session-key。
1.通过wx.login,获取res.code,将其发送给腾讯服务器,获取session_key
//app.js里面
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
if (res.code) {
//发起网络请求
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
//这里提一下我中的坑,appid和appsecret可以通过测试号来获取,自己的appid和appsecret放在这里好像也获取不了,测试号获取怎么弄,在微信开发者工具上面有个测试号,点击进去可以进入小程序的开发者文档,里面有个申请测试号,。只需访问 申请地址 ,点击蓝色的申请地址,里面链接中就有appid和secret。当然你能用自己正式的appid和secret成功获取到了session-key,就忽略这句话吧
appid: 'wxb805796eb9*****',//小程序的ID
secret: 'eaed34b32421*******',//小程序的密钥
js_code: res.code,
grant_type: 'authorization_code'
},
method: 'GET',
header: {
'content-type': 'application/json' // 默认值
},
success: function (response) {
console.log(response);
var openId = response.data.openid;
var session_key = response.data.session_key; //这里就获取了session-key
console.log(session_key + "//?????" + openId);
var app = getApp();
app.globalData.openid = openId;
app.globalData.session_key = session_key;
typeof cb == "function" && cb()
},fail: function (res) {
console.log('获取openId、sessionKey失败!' + res.errMsg)
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
})
考虑到某些小伙伴的appid和secret没有或者无法有效获取到session-key,自己有没有获取到session-key控制台打印一下就知道了,如果appid和secret无法获取到session-key的话,可以使用测试号提供的appid和secret来尝试,我反正使用测试号获取到的,这里提供通过测试号获取appid和secret的过程。
2.获取session_key后,现在来获取encryptedData,iv。
//创建一个getphone.wxml文件
const app = getApp()
var WXBizDataCrypt = require('../../utils/RdWXBizDataCrypt.js');
Page({
canIUse: wx.canIUse('button.open-type.getUserInfo'),
/**
* 页面的初始数据
*/
data: {
AppId: ''
},
blindgetPhone: function(e) {
// 获取session-key
var session_key = app.globalData.session_key;
var openid = app.globalData.openid;
var AppId = "wxb805796eb******";
// 获取encryptedData、iv这两个参数
var encryptedData = e.detail.encryptedData;
var iv = e.detail.iv;
console.log(session_key + "///")
if (e.detail.errMsg == 'getPhoneNumber:fail user deny') {
wx.showModal({
title: '提示',
showCancel: false,
content: '手机号码未授权,请授权后再使用',
success: function(res) {}
})
} else {
//检查sessionkey状态,如果用户session-key无效则重新登录获取session-key,
// 如果有效,则通过传入三个参数encryptedData,iv,session-key进行手机号解析
wx.checkSession({
success: function() {
console.log("session_key 未过期,并且在本生命周期一直有效");
console.log("-----" + AppId + "------" + session_key + "---" + encryptedData + "" + iv);
var pc = new WXBizDataCrypt(AppId, session_key)
var data = pc.decryptData(encryptedData, iv)
app.globalData.phoneNumber = data.phoneNumber
console.log(app.globalData.phoneNumber + "------------");
wx.setStorageSync('phoneNumber', data.phoneNumber);
}
})
}
}
3.复制到这里了,会发现1个陌生的代码, WXBizDataCrypt,好的,接下来创建utils目录,在utils里面创建一个WXBizDataCrypt.js以供上面代码使用,在WXBizDataCrypt.js里面又引用了别的组件,我也提供一个该文件夹下载地址给你(https://github.com/gwjjeff/cryptojs/archive/master.zip),将该文件夹也放在utils目录里面,也可以参考别人的文章了解详情https://www.cnblogs.com/cai-rd/p/6816849.html
创建WXBizDataCrypt.js,别问我,整个代码复制过去就行,我也没理清楚
/**
* Created by rd on 2017/5/4.
*/
// 引入CryptoJS
var Crypto = require('cryptojs-master/cryptojs.js').Crypto;
var app = getApp();
function RdWXBizDataCrypt(appId, sessionKey) {
this.appId = appId
this.sessionKey = sessionKey
}
RdWXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
// base64 decode :使用 CryptoJS 中 Crypto.util.base64ToBytes()进行 base64解码
var encryptedData = Crypto.util.base64ToBytes(encryptedData)
var key = Crypto.util.base64ToBytes(this.sessionKey);
var iv = Crypto.util.base64ToBytes(iv);
// 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充
var mode = new Crypto.mode.CBC(Crypto.pad.pkcs7);
try {
// 解密
var bytes = Crypto.AES.decrypt(encryptedData, key, {
asBpytes: true,
iv: iv,
mode: mode
});
var decryptResult = JSON.parse(bytes);
} catch (err) {
console.log(err)
}
if (decryptResult.watermark.appid !== this.appId) {
console.log(err)
}
return decryptResult
}
module.exports = RdWXBizDataCrypt
接下来提供第二种方式,通过java代码来实现手机号解析。
const app = getApp()
Page({
canIUse: wx.canIUse('button.open-type.getUserInfo'),
/**
* 页面的初始数据
*/
data: {
},
getPhoneNumber: function(e) {
// 获取session-key
var that = this;
var session_key = app.globalData.session_key;
console.log(session_key + "///")
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
if (e.detail.errMsg == 'getPhoneNumber:fail user deny') {
wx.showModal({
title: '提示',
showCancel: false,
content: '手机号码未授权,请授权后再使用',
success: function(res) {}
})
} else {
//检查sessionkey状态,如果用户session-key无效则重新登录获取session-key,
// 如果有效,则将encryptedData,iv,session-key发送给开发中服务器进行数据解析
wx.checkSession({
success: function() {
console.log("session_key 未过期,并且在本生命周期一直有效");
wx.request({
url: 'http://localhost:8080/getPhoneNumber',
data: {
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
sessionKey: session_key
},
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function(res) {
console.log('解析手机号码成功');
console.log(res);
app.globalData.phoneNumber = res.data.phoneNumber
console.log(app.globalData.phoneNumber + "------------");
},
fail: function(res) {
console.log("解析手机号失败")
}
})
},
fail: function() {
console.log("session_key 已经失效,需要重新执行登录流程");
wx.login({
success: function(res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session',
data: {
appid: 'wxb805796*******', //小程序的ID
secret: 'eaed34b32421c150c***********', //小程序的密钥
js_code: res.code,
grant_type: 'authorization_code'
},
method: 'GET',
header: {
'content-type': 'application/json' // 默认值
},
success: function(response) {
var openId = response.data.openid;
var session_key = response.data.session_key
wx.request({
url: 'http://localhost:8080/getPhoneNumber',
data: {
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
sessionKey: session_key
},
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function(res) {
console.log('获取手机号码成功');
console.log(res);
app.globalData.phoneNumber = res.data.phoneNumber
}
})
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
}
})
}
java后台代码,需要的jar包我就不说了,也说不清楚,自己靠工具提示下载吧。
import org.apache.shiro.codec.Base64;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
@Controller
public class GetPhone {
/*用户手机号解析*/
@RequestMapping("/getPhoneNumber")
@ResponseBody
public String getPhoneNumber(String encryptedData, String iv, String sessionKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
System.out.println(encryptedData + "-------" + iv + "-------" + sessionKey);
byte[] encData = Base64.decode(encryptedData);
byte[] keyByte = Base64.decode(iv);
byte[] key = Base64.decode(sessionKey);
AlgorithmParameterSpec ivSpec = new IvParameterSpec(keyByte);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);// 初始化
byte[] resultByte = cipher.doFinal(encData);
if (null != resultByte && resultByte.length > 0) {
String result = new String(resultByte, "UTF-8");
System.out.println(result);
return result;
}
return null;
}
完结了。