在實際的網站設計中我們經常會遇到使用者資料的驗證和加密的問題,如果實現單點,如果保證資料準確,如何放著重放,如何防止CSRF等等
其中,在所有的服務設計中,都不可避免的涉及到Token的設計。
目前,基於Token的產生方,我們把Token產生分為兩種類型。
1、基於使用者/網站,可見的加密請求方式
2、基於伺服器間通訊的不可見加密請求方式(API Token)
其中,網頁/APP訪問又分為 登入態和非登入態 兩種請求區別。
(非登入態請求要求使用者訪問頁面時會隨機產生唯一且有時效性的token,該token在每次請求時都是不同)
(登入狀態中,token會儲存一定的時間,頁面中的token會作為使用者身份識別)
雖說兩者作用有一定的區別,但是實現的原理是相同的。
1、非登入狀態
原理:
非登入狀態中,防止伺服器資源被重複利用,我們在前端頁面中會添加一步建立初始Session的過程,該過程來確保下一步關鍵請求不被利用。
一般這種驗證方式用於體驗頁面,如:視頻播放頁面,項目或功能展示頁面等
優點:
目的就是有點,防止token被盜用,重複請求伺服器資源(類似於抖音視頻播放時的簽名演算法作用)
缺點:
所有前端加密都有被破解的可能,需要對具體的JS進行混淆,同時添加https和來源判斷
2、登入狀態
登入狀態的Token
登入態token 通過伺服器產生:
Encode(MD5({session}+{使用者資訊摘要}+{Timestamp})+TimeStamp)
聯合Redis 重新整理使用者登入時間長度及token有效時間長度。Redis設定自動到期時間。
驗證方法:
decode(Token)->sign+TimeStamp
if(sign===MD5({session}+{使用者資訊摘要}+{Timestamp})){
// XXXX
}
(防止弱語言的判斷邏輯,驗證PW和Token要用=== 強型別判斷)
退出登入:刪除Redis 索引值
單點登入:重新登入時資訊更新,使用者資訊摘要不變,自動重新整理Redis的Token值和有效期間
3、API 非對稱式加密
api的非對稱式加密常用於伺服器之間的請求,雙方各自儲存私密金鑰和公開金鑰。API介面中常體現於【APP_ID,APP_KEY|APP_SECRET】
Token 產生演算法:
/** * 產生token * @param $user_info string * @param $app_key string app_key * @param $app_id int app_id * @return string */ public function generate_access_token($user_info , $app_key, $app_id) { $time = time(); $sign = sha1($time . $advertiser_id . $app_key); $token = base64_encode("{$time},{$user_info },{$app_id},{$sign}"); return $token; }
Token解析方法:
解密的方法中對時效性做了一分鐘的驗證,實際項目中可以根據情況開放失效的設定。
/** * 解析token * @param $access_token * @return array */ public function analysis_access_token($access_token) { $token_array = base64_decode($access_token); $token_array = explode(',', $token_array); $time = $token_array[0]; $user_info = $token_array[1]; $app_id = $token_array[2]; $sign = $token_array[3]; if ($time < (time() - 60) || $time > (time() + 60)) { call_back(1101, 'Access Token expire !token=' . $access_token); } global $third_platform_app_key;// app_id-app_key對應表 if (!isset($third_platform_app_key[$app_id])) { call_back(1101, 'Access Token App id Error!token=' . $access_token); } $app_key = $third_platform_app_key[$app_id]; $local_sign = sha1($time . $user_info . $app_key); if ($local_sign === $sign) { return [ 'access_token' => $access_token, 'user_info' => $user_info, 'time' => $time, 'app_id' => $app_id, 'app_key' => $app_key, ]; } else { call_back(1101, 'Access Token Sign Error!token=' . $access_token); } }
改Token方式要求每次請求都需要產生新的token來確保請求的時效性
另外:為了加強API介面請求的完整性,我們也會對請求內容進列欄位排序後摘要驗證。(詳情參考:open.taobao.com/docV2.htm?docId=101617&docType=1)
今天的普及到這裡就結束啦,謝謝大家,也歡迎大家留言討論。