業務方視角,接入登入賬號體系
前言:
上一篇我們介紹過了如何使用php+jwt。講述如何製作一個一站式登入平臺。打通各個業務方之間的賬號壁壘。那麼現在我就來介紹下。從業務方的角度,如何去接入一個登入中心
流程

使用者訪問業務方地址
接入登入中心
首先我介紹下域名:
- 登入中心的url是:tp.login.com:81
- 接入方的域名是:tp.admin.com:81
兩個完全不一樣的域名,也不存在session共享什麼的。那麼,現在我要把我的tp.admin.com:81接入到tp.login.com:81的賬號體系中去。
一:設計回撥地址的路由
由於我這次寫的一個demo。就是直接在index模組下login控制器裡寫了個callback方法。如果在生產環境下的話還是推薦強制路由。這樣url看上去美觀點。好那麼我們回撥地址就是tp.admin.com:81/index.php/index/login/callback( 這裡有個細節,這個回撥的地址,是不需要做登入驗證的,因為剛回調回來的時候,cookie中還沒有密文。所以這個控制器不繼承有登入驗證的那個控制器 )
二:申請應用
好了,既然都是我寫的demo。就不存在申請不申請了。不過正規的流程應該是接入方會向登入中心的管理員,申請。告知回撥地址。登入中心的管理員在app中添加回調地址,隨機字串作為祕鑰,並獲得appid。
三:開始開發
首先呢,我們將登入中心的地址,和分配給我們的appid 和app_key存到配置檔案中方便使用
配置檔案
隨後,我們既然是接入別人的登入中心,那就不用自己寫登入了。直接寫登入驗證。
登入驗證一般來說都會是寫到一個控制器基類的__construct()方法裡面
class Base extends Controller { public $uid; public $name; public function __construct() { /** * 1.判斷是否有cookie * 2.沒有cookie,拼接回調地址和appid * 3.如果有cookie,解密code。驗籤 * 4.延籤失敗刪除cookie * 5.驗籤成功,初始化uid,name */ try{ $request=request(); $authCode= cookie('authCode'); if (empty($authCode)) { //拼接回調地址和appid $appid=config('sso.appid'); //獲取當前請求地址 $callback_url=$request->url(true); //去配置檔案中獲取登入中心地址 $login_url=config('sso.login_url'); //拼接跳轉地址 $url=$login_url."?appid={$appid}&callback_url=".urlencode($callback_url); $this->redirect($url); }else{ //如果有cookie //解密驗籤並取得cookie中的uid $uid=Auth::getUidByJwt($authCode); $this->uid=$uid; } }catch (Exception $e){ $this->error($e->getMessage()); } } }
重點看看驗籤獲取uid的方法。其實這個方法是一個基礎方法擴充套件而成的。直接來看程式碼
/** * 從jwt中獲取某個欄位 * @param $token * @param $key * @return bool * @throws Exception */ public static function getDataByJwt($token, $key) { //將token字串初始化 token物件 $tokenObj = (new Parser())->parse((string)$token); //例項化加密物件 $signer = new Sha256(); //使用配置中的祕鑰驗籤 $result = $tokenObj->verify($signer, config('sso.app_key')); if (!$result) { //驗籤失敗 //刪除cookie,避免無限重定向 cookie('authCode'); throw new Exception('驗籤失敗'); } //使用檢查過期時間的方法判斷登入是否過期 if ($tokenObj->isExpired()) { cookie('authCode'); throw new Exception('登入過期'); } //獲取想要的資料 $data = $tokenObj->getClaim($key); if ($data) { return $data; } else { return false; } } /** * 使用基礎方法,獲取uid * @param $token * @return bool * @throws Exception */ public static function getUidByJwt($token) { return self::getDataByJwt($token, 'uid'); }
其實jwt的包提供了非常豐富的方法,基本對密文沒有太多的處理,驗籤之類的方法都準備好了。使用成本相當的低
上面介紹了驗證登入的建構函式,還有一個地方別忘了。那就是我們最開始申請應用的那個回撥地址。那個方法需要負責以下幾個動作
- 獲取登入中心傳遞過來的引數
- 驗證code簽名
- 將code寫入cookie
- 從定向到使用者最初訪問的地址
下面來看程式碼
class Login extends Controller { public function callback($code,$redirect) { try{ //驗籤並取出uid $uid= Auth::getUidByJwt($code); //uid存在且回撥地址存在 if($uid&&$redirect){ //寫入cookie cookie('authCode',$code); //重定向到使用者最初訪問的地址 $this->redirect($redirect); }else{ //避免重定向 cookie('authCode'); $this->error('登入過期'); } }catch (Exception $e){ //避免重定向 cookie('authCode'); $this->error('登入過期'); } } }
當這一次重定向到使用者訪問的頁面時,又會觸發登入驗證。這個時候,我們已經寫好了cookie。cookie也是合法的。就會成功的取出使用者的uid。下次使用者訪問這個應用的別的方法時,也攜帶這個cookie就可以正常使用了。更方便的是,我們在登入中心這個域名下還儲存了一份cookie,當去訪問別的應用時,別人的應用認為你沒有登入重定向到登入中心後,就會檢測到有cookie值並帶上值重定向回別的應用。實現免登入
下面簡單展示下效果

l瀏覽器進入我們寫的tp.admin這個應用
檢測沒有登入,重定向到登入中心

登入中心
隨後輸入密碼賬號,點選登入

點選登入
然後又經歷了兩次重定向
一次是重定向到註冊的回撥地址,帶上code
一次是寫好cookie之後就重定向到最初訪問的地址,我們從瀏覽器上也觀察出回到了我們最初輸入的那個地址

回到最初訪問的地址
並且我在首頁輸出了使用者的id 1 這是通過解密jwt得到的uid
現在我們在重新整理一下頁面、由於已經有cookie儲存了。所以不會再做重定向了。

登入後再訪問首頁
我們還可以試試把tp.admin.com這個域名下的cookie刪除,然後在訪問首頁。看會發生什麼

刪除cookie
我們重新整理下tp.admin.com 的主頁

又是一波瘋狂的重定向
我們一步一步分析
- 重定向到了登入中心
- 登入中心發現有cookie存在就重定向到回撥地址,帶上cookie和redirect
- 回撥地址,驗籤通過,初始化uid 並且重定向到最初訪問的地址,也就是首頁
雖然做了幾次重定向,但是對於使用者來說是察覺不出來的。他體驗到的是不需要登入的方便與快捷
好了今天的介紹接入登入中心就寫到這裡了。雖然還有些不完善的地方,不過這個機制是非常值得學習和可靠的。如果有不對的地方,望大神指正。感謝!
以上