小程式的登入和資料解密全解析

小心夾手發表於2018-04-20

不知不覺已經一個月沒有寫東西了,墮落的日子居然過的這麼心(chou)安(bu)理(yao)得(lian),罪過啊。

好了,回到正文來,聊我們們的小程式。

致敬

登入大部分邏輯程式碼統統來自手把手教會你小程式登入鑑權

登入流程

小程式的登入和資料解密全解析

上圖是官方給出的登入流程,我們來捋下邏輯。

1、使用者使用wx.login獲取臨時code,有效期為5分鐘

2、將臨時code傳到我們自己的後端服務,呼叫微信的API獲取使用者的session_keyopenid

3、後端自定義新的金鑰並關聯返回的session_keyopenid,將新的金鑰返給前端

4、前端傳送請求的時候,帶著金鑰,後端進行解析後返回資料

session_key和openid

1、session_key會話金鑰,用來確定會話的操作的有效性和用來加密解密使用者資料,伺服器自己儲存即可,不應該將金鑰返給前端和對話使用

2、openid使用者唯一標識,同樣只用於伺服器,可以用來標識使用者的唯一性

接下來,我們說下它們的獲取,通過服務端呼叫微信API獲取

API:https://api.weixin.qq.com/sns/jscode2session

引數如下:

小程式的登入和資料解密全解析

// 小程式頁面
wx.login({
	success:(ret)=>{
		wx.request({
			url: 'http://test.com', // 後端伺服器
			data:{
				code : ret.code
			}
		})
	}
})

複製程式碼

後端服務我們使用request模組來傳送請求

// 後端服務
let options = {
  url: 'https://api.weixin.qq.com/sns/jscode2session',
  qs:{
      appid: appid,  
      secret: secret,
      js_code: code,
      grant_type:'authorization_code'
  }
}

// 預設請求方式是get
request(options, (err, response, body) => {
	if(err) return err
	return body  // {openid:'openid', session_key:'session_key'} 不是真正的返回 看下面的程式碼
})

複製程式碼

生成新的金鑰 skey

上面我們獲取了session_key和openid,下文兩個字斷稱keyID,接下來我們生成一個新的金鑰返回前端並將新金鑰關聯keyID。

我們使用crypto模組的sha1演算法生成金鑰

const crypto = require('crypto')

function getShaKey(data){
	return crypto.createHash('sha1').update(data, 'utf8').digest('hex')
}
複製程式碼

上面的程式碼返回我們就改成這個新的skey,前端將這個金鑰存在storage裡面,請求的時候帶上這個skey,就完成了自定義登入態。

wx.checkSession

用來校驗當前使用者的session_key是否有效,微信不會把session_key的有效期告知開發者,使用者越頻繁使用小程式,session_key有效期越長。

wx.checkSession({
	success:function(){  // 當前session_key有效
		... // 可以寫我們的業務程式碼
	},
	fail:function(){   // 當前session_key已過期
		wx.login()  // 重新登入,獲取新的session_key
	}
})
複製程式碼

當session_key過期的時候,我們呼叫登入API,更新session_key生成新的skey,並關聯二者關係。

工具函式的封裝

前面我們將流程大概串了下,接下來我們把上面的流程寫成寫成公用的函式


// 驗證session_key狀態
function checkSession(){
	return new Promise((resolve, reject) => {
		wx.checkSession({
			success:function(){
				resolve(true)
			},
			fail:function(){
				reject(false)
			}
		})
	})
}

// 登入

function login(){
	return new Promise((resolve, reject) => {
		wx.login({
			success: (ret) => {
				wx.request({
					url:'本地服務地址',
					method: 'POST',
					data:{
						code: ret.code
					},
					success: (response) =>{
						wx.setStorageSync('skey', response.data.key)  // 將skey存在storage裡面
						resolve(response.data.key)
					}
					
				})
			}
		})
		
	})
}

// 請求

function ajax(url, data, method="GET", config={}){
	let skey = wx.getStorageSync('skey') // 獲取skey
	if(!skey){  // 沒有skey,首次登入
		return new Promise((resolve, reject) => {
			login()
			reject('請登入')
		})
	} else {
		return new Promise((resolve, reject) => {
      checkSession().then( _=> {
        if (_){ // session_key有效
          wx.request({
            url,
            method: method.toLocaleUpperCase(),
            data,
            header: Object.assign({}, { skey }, config),
            success: (ret) => {
              resolve(ret.data)
            }
          })
        } else { // session_key失效
          login()
          reject('session_key失效')
        }
      })
    })

	}
}

複製程式碼

後端程式碼

後端使用koa框架,程式碼見文末github地址

解密

官方提供了多種程式語言的示例程式碼點選下載

這裡我們使用微信運動API為例

var app = getApp()  // 我們將工具函式都放在了app的示例上面
Page({
	onLoad:function(){
		app.Util.login().then(_ => {  // 先登入然後獲取資料
      this.getrunData()
    })
	},
	getrunData(){
    wx.getWeRunData({
      success: (ret) => {
        app.Util.ajax('本地服務地址', { iv: ret.iv, data: ret.encryptedData}, 'post').then(_=>{
          console.log(_)
        }, (err)=>{
          console.log(err)
        })
      }
    })
  },

})

複製程式碼

返回結果如下

小程式的登入和資料解密全解析

以上,我們完成了小程式簡單的登入鑑權和資料解密

效果圖鎮樓

小程式的登入和資料解密全解析

結尾

登入鑑權我們只是將使用者狀態放在了記憶體裡,實際專案中肯定要放在資料庫中,可以拜讀下大神文章,裡面說到了資料庫的操作。

再次致敬

本文完整程式碼請戳github

相關文章