微信小程式登入換取token
前言:
這次主要是介紹些業務邏輯,技術點倒是沒有多少。不過在開發中,優秀的程式設計思路同樣是非常值得學習的。
最近小程式可以說在開發屆狠狠的火了一把。微信小程式可以開發遊戲,騰訊率先帶頭,做出了一個跳一跳也是點爆朋友圈。所謂落後就要捱打,那麼今天就開始學習小程式的一些小知識吧(本文基於十年磨一劍的tp5)
目錄:
- 微信登入換取token的流程
- 如何將code變成openid和session_key
- 丟擲錯誤異常和派發令牌
一:微信登入換取token的流程
多說無益,直接上圖

小程式獲取token.png
二:如何將code變成openid和session_key
我們後端開發人員對這個業務是從接受code開始的,由客戶端發來一個code碼。
我們接受後先進行驗證
//建立獨立驗證器,呼叫驗證器中的驗證方法 TokenCheck::instance()->goCheck();
如果不是很清楚驗證器的用法的朋友 可以先看看我之前寫的驗證器的使用
驗證規則很簡單,就是判斷不為空就可以了
下一步就是我們需要把code換取openid 和session_key了
首先我們需要在建立一個service層的類,(為什麼要使用service層呢?主要是我為了讓模型層粒度細一些。業務比較複雜的就放在service層。這樣比較利於後期修改和升級)
class UserToken extends Token { protected $wxAppId; protected $wxAppSecret; protected $wxLoginUrl; //建構函式中賦值成員變數 public function __construct($code) { $this->wxAppId = config('wx.app_id'); $this->wxAppSecret = config('wx.app_secret'); $this->wxLoginUrl = sprintf(config('wx.login_url'), $this->wxAppId, $this->wxAppSecret, $code); } }
寫一個建構函式,讓在物件生成的時候就賦值成員變數方便使用,這裡的appid和appsecret 都是在微信申請小程式的時候就有了的。這裡就不介紹了。之前我是把他們全部存在我的配置檔案的。使用tp5提供的config函式將他們提出來。最後使用 sprintf方法,將這些引數拼接到wxLoginUrl中,方便我們訪問。
熟悉Oauth2.0的朋友都知道,拿到這個url其實就是微信的一個介面,我們去換取授權。
下面我們建立一個getUserToken方法
/** * 獲取使用者的令牌方法 * @throws Exception */ public function getUserToken() { //呼叫公共函式中的http方法(也就是curl的方法,我也是在網上抄的。存放在common.php中就可以直接用了) $result = http($this->wxLoginUrl, 'post'); //判斷連線是否成功 if ($result[0] == 200) { //將返回的json處理成陣列 $wxResult = json_decode($result[1], true); //判空 if (empty($wxResult)) { throw new Exception('獲取session_key,openID時異常,微信內部錯誤'); } else { //判斷返回的結果中是否有錯誤碼 if (isset($wxResult['errcode'])) { //如果有錯誤碼,呼叫丟擲錯誤方法 $this->_throwWxError($wxResult); } else { //沒有錯誤碼,呼叫私有的派發token方法 $token = $this->_grantToken($wxResult); return $token; } } } else { throw new Exception('連線微信伺服器失敗'); } }
寫好了,方法之後,只需要在控制器中呼叫這個getUserToken方法就可以了。
大家可能會問,那個_throwWxError和_grantToken方法是幹什麼的?
可能大家也看出來了,這個getUserToken方法中我們一個獲取到了微信返回的結果,也就是$wxResult變數中的資料。如果不出別的意外那麼,裡面就有我們需要的openid和session_key。這不過,介紹到這裡,我們還沒有開始使用他們
三:丟擲錯誤異常和派發令牌
這裡兩個其實就是兩個方法,重點是派發令牌。這裡的丟擲異常。我準備單獨寫一次介紹。
/** * 微信獲取open_id失敗,丟擲異常方法 * @param $wxResult * @throws WxException */ private function _throwWxError($wxResult) { thrownew WxException( [ 'message' => $wxResult['errmsg'], 'errorCode' => $wxResult['errcode'] ] ); }
我們來看_grantToken方法
我們將微信返回給我們的資料,轉換為陣列後,儲存到$wxResult中,在呼叫派發令牌方法時,直接傳入。
下面的程式碼中有個 User 類呼叫的 getUidByOpenId 方法,這裡是User模型上封裝的一個查詢方法,就是看User表中是否有這個openid,如果有返回uid
如果資料庫中沒有uid的話,說明是新使用者,則在資料庫中插入一條資料,返回新插入的主鍵 id
/** * 派發User 令牌 * @param $wxResult * @return string * @throws Exception */ private function _grantToken($wxResult) { //拿到open_id $openId = $wxResult['openid']; //判斷open_id是否存在 $id = User::getUidByOpenId($openId); //如果資料庫中不存在 if (!$id) { //新增一條記錄,返回新建立的id $id = User::createUser($openId); if (!$id) { throw new Exception('新增一條User失敗'); } } //拼接資料為一個數組。(這個方法就是將wxResult中的openid和session_key取出,然後和使用者id一起放進一個數組) $tokenValue = $this->_splicingValue($wxResult, $id); //製作令牌 //存入快取 $token = $this->_saveCache($tokenValue); //返回token return $token; }
下面我們來看看_saveCache方法
我們將拼接成一個數組的資料$tokenValue直接傳入方法中,呼叫一個隨機字串方法,將這個隨機字串當做key,把傳入我使用者資料序列化之後當作value,然後根據配置裡的快取過期時間,來存入快取。
/** * 將令牌存入快取,返回token * @param $tokenValue * @return string * @throws TokenException */ private function _saveCache($tokenValue) { //呼叫父類中的隨機字串方法 $key = parent::_makeToken(); //序列化包含id,openid,sessionKey的陣列 $value = serialize($tokenValue); //在配置中取出儲存時間的配置 $expriesTime = config('setting.expires_in'); //存入快取 $result = cache($key, $value, $expriesTime); //如果存入失敗,丟擲異常 if (!$result) { throw new TokenException( ['errorCode' => 10003, 'message' => 'Token save fail'] ); } //返回隨機字串(也就是要返回給客戶端的token) return $key; }
隨機字元方法,為了提高token的安全性,讓別人不那麼容易的複製我們的token。我就寫了這樣的一個方法,大家如果有安全性更好的方法也可以使用自己想的。我就不介紹了 看程式碼吧
/** * 構建token隨機字串 */ public function _makeToken() { //隨機抽取32位字串方法,儲存在common.php中 $randChar = randomkeys(32); //時間戳 $timestamp = time(); //配置中的鹽值 $salt = config('secret.token_salt'); //拼接之後sha1加密 return sha1($randChar . $timestamp . $salt); }
這裡我們就將隨機生成的隨機字串返回到service層,service層再返回給控制器,控制器就可以返回給客戶端了
看下完整的控制器吧
public function getToken($code = '') { //建立獨立驗證器,呼叫驗證器中的驗證方法 TokenCheck::instance()->goCheck(); $utObj = new UserToken($code); $token = $utObj->getUserToken(); return ['token'=>$token]; }
這樣一個小程式登入換取token的流程就走完了。這個業務呢是藉助微信伺服器中的openid來作為唯一標識來派發token,如果不是微信的專案的話,我們同樣的可以是微博登入,qq登入等第三方登入。或者自己的資料庫中的id來作為唯一標識。同樣可以派發token。
這裡只是介紹了token的派發,還有一些token的應用,有時間的時候再寫吧。今天就介紹到這裡。如果有什麼沒有寫對的地方,希望大神指正,我們共同學習。
以上