根据官方文档中的open-data部分的介绍,为了保护用户隐私,小程序只向开发者提供了openGid。它用来在某个特定小程序中唯一标识一个群,并且可以通过open-data组件来向用户展示群名称(并不能拿到群名称只是展示而已)。可以先看这篇文章:https://www.ifanr.com/minapp/832760 看完之后,大家可以基本理解这个流程。本文主要介绍通过1044状态码进入小程序(即通过其他群成员分享到群中的小程序小卡片进入)如何拿到群信息。
一、第一条线索:查看官方文档关于转发的部分,通过1044进入时,小程序就可以额外获取到 shareTicket。有了 shareTicket,我们就可以通过调用 wx.getShareInfo 函数,获取到目标微信群的encryptedData和iv。注意这是用来获得群id的关键线索。那么我们接着看官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/signature.html#wxchecksessionobject。这里提供了解密算法的下载。然后我们将它下载下来并打开查看node部分。解密算法如下所示:
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
给出的demo样例如下所示:
var WXBizDataCrypt = require('./WXBizDataCrypt')
var appId = 'wxee6e3f1721fc1c61'
var sessionKey = 'Sc7PC6lZ3IPgcx7h+ZQMvA=='
var encryptedData="7deXSrzADGzvcwWjhWYded3UHMtusTG9kiX5jW14uSSFfbyzqW5xD3SP2x0r+ZSBuMJMCkxGHsgIEBvTDuKAeo5D44hdcIFv9OoYB/pexWDElpVqqxhHvtH22hax2qr3pro4fX2R2Tz6Vw3CL1ZaTQ=="
var pc = new WXBizDataCrypt(appId, sessionKey)
var data = pc.decryptData(encryptedData , iv)
console.log('解密后 data: ', data)
这里我们可以得知:只要为这个算法提供四个输入:appid,session_key,encryptedData和iv,它便可以将openGid返回给我们。问题似乎变得清晰了。
二、那么我们分别通过什么方式可以得到appid,session_key,encryptedData和iv呢?
1、首先是appid,我们打开腾讯云提供的phpadmin数据库操作界面,可以发现在cAuth数据库的cAppinfo表中保存了appid。GOT IT!!如下所示
3、然后是encryptedData和iv了,它们在小程序app的onshow或onlaunch方法中,可以拿到,如下所示,我们拿到后,使用wx.setStorageSync将其保存下来
App({
onLaunch: function (ops) {
qcloud.setLoginUrl(config.service.loginUrl)
if (ops.scene == 1044) {
console.log(ops.shareTicket)
wx.getShareInfo({
shareTicket: ops.shareTicket,
complete(res) {
console.log(res)
wx.setStorageSync('encryptedData', res.encryptedData)
wx.setStorageSync('iv', res.iv)
}
})
}
}
})
我们可以通过小程序开发工具对保存下来的值进行查看
然后通过qcloud.request方法,将它们放到options.data对象中发送给后端即可,然后在success回调函数中,将openGid赋值给data.open_gid,如下所示
doGroup:function(){
var that=this
util.showBusy('发送群信息中...')
var options ={
url:config.service.groupUrl,
login:false,
// method:'POST',
data:{
encrytedData: wx.getStorageSync('encryptedData'),
iv:wx.getStorageSync('iv')
},
success(result) {
util.showSuccess('请求成功完成')
console.log('request success', result)
that.setData({ open_gid: result.data.data.openGId})
console.log(that.data.open_gid)
},
fail(error) {
util.showModel('请求失败', error);
console.log('request fail', error);
}
}
qcloud.request(options)
},
三、后台拿到后,直接调用我们前面下载的解码函数解码即可得到openGid,具体代码如下:
1、在page.json的dependencies中添加对解码算法使用的crypto包的依赖如下图所示:
2、在route文件夹的index.js下添加如下代码:
3、将前文中的解码算法复制到controllers文件夹下(这种做法不够好,但可以解决问题)
4、再在controllers文件夹中新建group.js,输入如下代码
var WXBizDataCrypt = require('./WXBizDataCrypt')
const qcloud = require('../qcloud')
const { mysql } = qcloud
module.exports = async (ctx, next) => {
if (ctx.state.$wxInfo.loginState === 1) {
// loginState 为 1,登录态校验成功
try{
const appInfo = await mysql('cAppinfo').select('*')//[msg|从数据库取得appInfo对象]
const appId=appInfo[0].appid//[msg|从appInfo上拿到appId的值]
const { 'x-wx-skey': skey } = ctx.req.headers//[msg|从请求头拿到skey]
const sessionInfo = await mysql('cSessionInfo').select('*').where({ skey: skey })//[msg|根据skey从数据库拿到]
const sessionKey = sessionInfo[0].session_key//[msg|根据skey拿到sessionkey]
const encryptedData = ctx.query.encrytedData//[msg|从query中拿到encryedData]
const iv = ctx.query.iv//[msg|从query中拿到iv]
const pc = new WXBizDataCrypt(appId, sessionKey)//[msg|初始化并调用解码器来解码]
const data = pc.decryptData(encryptedData, iv)
ctx.state.data = data//[msg|将得到的数据放到请求体中用于发给前端]
}catch(e){
ctx.state.code = -1
}
} else {
ctx.state.code = -1
}
}
四、写在最后面(LZ目前没有解决的问题)
1、LZ发现:在测试环境下,使用手机将测试版小程序分享到群中,每次拿到的openGid都是不同的
2、更不幸的是:将这个openGid绑定至open-data,如下所示,并不能获得群名称(所以我这七个小时都干了什么)
3、然后,使用微信web开发工具,通过下图方式编译进入,每次拿到的openGid都不一样
4、所以,在开发环境下,lz并没有解决openGid的问题,而且似乎也不知道该如何解决(如果有大神知道,请指教)