微信小程序的默認(rèn)demo其中有一段是涉及到用戶的用戶信息的,我們?cè)谛〕绦蚶镆部吹搅宋业念^像和昵稱(chēng)信息。
研究下他的代碼,主要在 app.js 文件中。
//app.js App({ onLaunch: function () { //調(diào)用API從本地緩存中獲取數(shù)據(jù) var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) }, getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ //調(diào)用登錄接口 wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } }, globalData:{ userInfo:null } }) |
上述代碼從15行開(kāi)始涉及到調(diào)用登錄接口。這里調(diào)用了小程序的api: wx.login 。這里說(shuō)明下,小程序給開(kāi)發(fā)者封裝好的API都是直接使用js的方法來(lái)調(diào)用,開(kāi)發(fā)者直接使用類(lèi)似 wx.login() 的方法就可以與微信的服務(wù)器進(jìn)行交互,開(kāi)發(fā)者不需要知道小程序框架到底調(diào)用了哪個(gè)地址,傳了哪些參數(shù)。
緊接著調(diào)用 wx.getUserInfo 接口,該接口可直接返回用戶數(shù)據(jù).具體調(diào)用方法可參考 官方文檔
為了查看返回結(jié)果,我們?cè)诖a18行位置插入兩句打印日志代碼,可以查看具體的結(jié)果。
wx.getUserInfo({ success: function (res) { console.log(res.userInfo) console.log(res.encryptedData) that.globalData.userInfo = res.userInfo |
可以看到控制臺(tái)中打印出了對(duì)應(yīng)的結(jié)果。
接下來(lái)的例子小豬將使用官方hello world的例子,一般在我們的程序中不會(huì)將用戶的標(biāo)識(shí)直接展示給用戶,作為演示,我們將本來(lái)顯示昵稱(chēng)的位置的下方顯示出該小程序?qū)?yīng)該用戶的openid。
這里我們看到通過(guò)上述接口獲取的信息都是一些比較基本的信息,包括:昵稱(chēng)、頭像地址、性別等公開(kāi)的數(shù)據(jù)。這些數(shù)據(jù)可以方便的顯示在用戶界面上,可是有時(shí)候我們需要系統(tǒng)的識(shí)別出該用戶,也就是需要該用戶的辨識(shí)。
在小程序的代碼中,服務(wù)器端代碼有兩種方式來(lái)獲取到用戶的openID。
直接調(diào)用 wx.login 接口,該接口會(huì)返回一個(gè)code字段,利用該code值可以向微信服務(wù)器開(kāi)放的API請(qǐng)求用戶的openid,例如下列flask代碼:
fromflaskimportFlask, request importrequests app = Flask(__name__) appid = 'wx8fa41e5f33e*****' secret = '47d4ed43a683f800e66169c09dd*****' @app.route('/user/getuserinfo', methods=['GET', 'POST']) defgetuserinfo(): code = request.data printcode url = 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code' % (appid, secret, code) r = requests.get(url) result = r.text return result if __name__ == '__main__': app.run(debug=True) |
配合小程序的代碼:
//app.js App({ onLaunch: function () { //調(diào)用API從本地緩存中獲取數(shù)據(jù) var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) }, getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ //調(diào)用登錄接口 wx.login({ success: function (r) { console.log(r) wx.request({ url: 'https://***.smallerpig.com/user/getuserinfo', data: r.code, method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT // header: {}, // 設(shè)置請(qǐng)求的 header success: function(res){ console.log('success') that.globalData.openid = res.data.openid console.log(res.data.openid) // success }, fail: function(res) { console.log('fail') console.log(res) // fail }, complete: function(res) { console.log('complete') console.log(res) // complete } }) wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } }, globalData:{ userInfo:null, openid:null } }) |
上述js的小程序代碼大致邏輯為:
在調(diào)用 wx.login 并且執(zhí)行成功之后將請(qǐng)求到的code值post到我們自己的服務(wù)器上面,在服務(wù)器上請(qǐng)求微信服務(wù)器的API,微信服務(wù)器得到正確值之后會(huì)得給到openid和session_key。
如下圖:
在之前的公眾號(hào)開(kāi)發(fā)時(shí),我們可以直接使用openId來(lái)作為用戶的標(biāo)識(shí),在小程序中我們同樣可以使用該字段。只是該字段沒(méi)有顯式的表示出來(lái),而是通過(guò)res.encryptedData里。
通過(guò)之前的截圖可以看出,encryptedData是通過(guò)加密的數(shù)據(jù),根據(jù) 官方文檔 解釋?zhuān)覀冎灰褂弥付ǖ乃惴▉?lái)解密就可以得到我們想要的openID。
解密算法如下:
官方也給出了幾種語(yǔ)言的 demo解密程序
通過(guò)這種方式不僅可以獲取到用戶的openid,也可以獲取到用戶的unionId。
方式一可以直接獲取到了用戶的openid,但是沒(méi)辦法獲取到unionId,如果咱們程序需要用到unionId的話就沒(méi)有辦法,肯定得用第二種方法了,如果只是為了獲取到openId那可以使用方式一來(lái)獲取。
不過(guò)方式二相比方式一相對(duì)復(fù)雜,需要通過(guò)第一步獲取到的session_key,再解密數(shù)據(jù)。也就是想要使用第二種方式的話其實(shí)第一種方法也得走一遍。
最后,從安全性來(lái)將當(dāng)然方式二更安全一點(diǎn)。
下面附上小程序的index.js和index.wxml:
var app = getApp() Page({ data: { motto: 'Hello World', userInfo: {}, openid:null }, //事件處理函數(shù) bindViewTap: function() { wx.navigateTo({ url: '../logs/logs' }) }, onLoad: function () { console.log('onLoad') var that = this //調(diào)用應(yīng)用實(shí)例的方法獲取全局?jǐn)?shù)據(jù) app.getUserInfo(function(userInfo){ //更新數(shù)據(jù) that.setData({ userInfo:userInfo, openid:app.globalData.openid }) }) } }) <!--index.wxml--> <viewclass="container"> <view bindtap="bindViewTap" class="userinfo"> <imageclass="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image> <textclass="userinfo-nickname">{{userInfo.nickName}}</text> <textclass="userinfo-nickname">{{openid}}</text> </view> <viewclass="usermotto"> <textclass="user-motto">{{motto}}</text> </view> </view> |
這一篇介紹了獲取用戶openid的兩種方式,并使用第一種方式結(jié)合flask框架寫(xiě)了一個(gè)demo程序。
其中還用到了小程序API當(dāng)中的一個(gè)非常重要的接口,就是 wx.request 。也就是通過(guò)該接口向我們自身的業(yè)務(wù)服務(wù)器請(qǐng)求數(shù)據(jù),有點(diǎn)類(lèi)似js中的ajax的作用,從《微信web開(kāi)發(fā)者工具》的調(diào)試界面也可以看出其實(shí)際上就是通過(guò)xhr的方式來(lái)請(qǐng)求我們的業(yè)務(wù)服務(wù)器。
另外需要說(shuō)明的是微信的小程序本身禁止使用ajax來(lái)請(qǐng)求網(wǎng)絡(luò)資源。
下一篇小豬將重點(diǎn)介紹使用方式二來(lái)解密用戶的數(shù)據(jù),服務(wù)器端代碼同樣使用flask來(lái)實(shí)現(xiàn)。