[小程式NO.1]如何在小程式開發工具提供的Node.js快速啟動模版的基礎上獲得微信群資訊
根據官方文件中的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下新增如下程式碼:
router.get('/group', validationMiddleware,controllers.group)//[msg|這裡填寫路由,和轉發給誰進行處理]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,如下所示,並不能獲得群名稱(所以我這七個小時都幹了什麼)
<open-datatype='groupName'open-gid='{{open_gid}}'></open-data>3、然後,使用微信web開發工具,通過下圖方式編譯進入,每次拿到的openGid都不一樣
4、所以,在開發環境下,lz並沒有解決openGid的問題,而且似乎也不知道該如何解決(如果有大神知道,請指教)