API 接口設(shè)計(jì)中Token設(shè)計(jì)討論

在實(shí)際的網(wǎng)站設(shè)計(jì)中我們經(jīng)常會(huì)遇到用戶數(shù)據(jù)的驗(yàn)證和加密的問題,如果實(shí)現(xiàn)單點(diǎn),如果保證數(shù)據(jù)準(zhǔn)確,如何放著重放,如何防止CSRF等等。

其中,在所有的服務(wù)設(shè)計(jì)中,都不可避免的涉及到Token的設(shè)計(jì)。

目前,基于Token的生成方,我們把Token生成分為兩種類型。

1、基于用戶/網(wǎng)站,可見的加密請(qǐng)求方式

2、基于服務(wù)器間通訊的不可見加密請(qǐng)求方式(API Token)


其中,基于非服務(wù)器端的請(qǐng)求,我們要根據(jù)實(shí)際的應(yīng)用場景進(jìn)行一定的自定義加工。
在本次討論中我們把非服務(wù)的請(qǐng)求分為了兩部分。

  • 需要登錄的登錄態(tài)Token
  • 不需要登錄的臨時(shí)態(tài)Token

兩種請(qǐng)求中:

1、非登錄態(tài)請(qǐng)求要求用戶訪問頁面時(shí)會(huì)隨機(jī)生成唯一且有時(shí)效性的token,該token在每次請(qǐng)求時(shí)都是不同。改方法用于當(dāng)不需要登錄界面的請(qǐng)求多且無法使用靜態(tài)頁面的時(shí)候使用,Token會(huì)在一定的時(shí)間內(nèi)失效,以此來防止被機(jī)器爬取不需登錄的界面

2、登錄狀態(tài)中,token會(huì)保存一定的時(shí)間,頁面中的token會(huì)作為用戶身份識(shí)別,同時(shí)登錄態(tài)的Token需要利用session和頁面信息來防止被利用。

雖說兩者作用有一定的區(qū)別,但是實(shí)現(xiàn)的原理是相同的。


1、非登錄態(tài) 客戶端Token

image.png
  • 其中簽名的算法中的{Session}是通過加密的信息,用于判斷當(dāng)前 頁面的請(qǐng)求。
  • {瀏覽器摘要}中會(huì)記錄訪問者的ip及瀏覽器信息,用于防止token被不同的機(jī)器使用

使用場景:

  • 媒體臨時(shí)訪問頁面,用于防止機(jī)器爬蟲獲取token后無限訪問其他界面
  • 動(dòng)態(tài)臨時(shí)界面,防止機(jī)器不斷獲取動(dòng)態(tài)臨時(shí)頁面信息中的數(shù)據(jù)

2、登錄態(tài)Token

登錄態(tài)的Token一般在用戶登錄之后由服務(wù)器產(chǎn)生,并保存在瀏覽器中,過期時(shí)間較長,用于保存用戶的登錄狀態(tài)。
同時(shí),我們也可以在該Token中加入一定的校驗(yàn)元素,例如瀏覽器信息,ip,獲取是Cookies

Token=Encode(MD5({session}+{用戶信息摘要}+{Timestamp})+TimeStamp)

如果對(duì)時(shí)效性較強(qiáng)的頁面登錄訪問,我們可以加入session的校驗(yàn),設(shè)置session的有效時(shí)間,能夠?qū)崿F(xiàn)自動(dòng)退出的校驗(yàn)功能。
TimeStamp用來校驗(yàn)Token的生成時(shí)間。

同時(shí),你用redis的Hset可以實(shí)現(xiàn)多點(diǎn)登錄和單點(diǎn)登錄的功能。

  • 單點(diǎn):登錄后自動(dòng)移除之前的token。
  • 多點(diǎn):登陸后添加用戶Token列表。
  • 退出:session 過期或移除redis

服務(wù)端驗(yàn)證Token:

sign+TimeStamp=Decode(Token)
if(sign===MD5({session}+{用戶信息摘要}+{Timestamp})){
  // XXXX
}

3、服務(wù)器間通訊API Token

在常規(guī)的API Token體系中,我們常使用短時(shí)過期Token(Oauth Token除外)。
通常 APIToken 是使用非對(duì)稱加密來實(shí)現(xiàn)token的生成,但是世界生產(chǎn)中,Token 的秘鑰會(huì)簡化成app_id,app_key等簡單的加鹽參數(shù),不過只要秘鑰保存合理,Token基本無法被破解。

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;
    }

其中 app_key和app_id是一對(duì)公鑰和私鑰,唯一且互相對(duì)應(yīng)。同時(shí)app_key一般作為私鑰保存。一般服務(wù)系統(tǒng)會(huì)提供修改app_key的功能,來解決app_key不小心被泄露的問題。

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);// 分隔符由Token生成算法決定
        $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)) { // 校驗(yàn)時(shí)間可以自定義
            call_back(1101, 'Access Token expire !token=' . $access_token);
        }

        global $third_platform_app_key;// app_id-app_key對(duì)應(yīng)表

        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);// 利用私鑰進(jìn)行簽名,驗(yàn)證有效性

        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方式要求每次請(qǐng)求都需要生成新的token來確保請(qǐng)求的時(shí)效性。

另外:為了加強(qiáng)API接口請(qǐng)求的完整性,我們也會(huì)對(duì)請(qǐng)求內(nèi)容進(jìn)行字段排序后摘要驗(yàn)證。(詳情參考:https://open.taobao.com/docV2.htm?docId=101617&docType=1

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容