我是怎么做App token認證的

使用Token來做身份認證在目前的移動客戶端上非常流行重罪,Token這個概念來源于OAuth認證樱哼,主要是在服務(wù)端實現(xiàn)。關(guān)于相關(guān)的原理剿配,同學(xué)們自行百度搅幅。在這里,我簡單介紹一下我是怎么具體實現(xiàn)的呼胚,重點描述token生成茄唐、token識別及token緩存。

注:SpringBoot版本請點擊這里蝇更,商用代碼比較復(fù)雜沪编,但是核心思想與本文一樣

生成Token

服務(wù)端接收客戶端傳遞的username和password等請求,在數(shù)據(jù)庫中檢查年扩,如果用戶名密碼匹配的話蚁廓,表示登錄成功,服務(wù)端生成并返回一個token訪問令牌常遂。

    public function login()
    {
        $data = array_merge($this->request->post(), []);

        // login with password
        $user = Db::name($this->table)->field($this->field_except, true)->where('name', $data['name'])->find();
        if ($user) {
            if ($user['pwd'] === EncryptService::password($data['pwd'])) {
                $this->onLoginSuccess($user);
            } else {
                parent::logic_failure('密碼不正確', 'user_wrong_pwd');
            }
        } else {
            parent::logic_failure('用戶不存在', 'user_not_exists');
        }
    }

    private function onLoginSuccess($user)
    {
        unset($user['pwd']);
        $token = Token::generateToken($this->request, $user);
        $ret = [
            'token' => $token['token'],
            'user' => $user
        ];
        $this->logic_success(null, $ret);
    }

在上面的代碼中纳令,登錄成功,服務(wù)端向客戶端返回token和user信息克胳。token是通過Token類的靜態(tài)方法generateToken來生成的平绩。

    public static function generateToken($request, $user)
    {
        // 1,生成包含用戶及設(shè)備信息的新token
        $data = [
            'uuid' => $request->param('uuid', ''),
            'uid' => $user['id'],
            'ip' => $request->ip(),
            'client' => $request->param('client', ''),
            'update_time' => ApiBase::_timestamp(),
        ];
        // json序列化
        $json = json_encode($data);
        // 加密token信息
        $key = md5(EncryptService::encrypt($json));
        $data['token'] = $key;
        // 2漠另,從數(shù)據(jù)庫查詢用戶的token捏雌,決定是update還是insert
        $token = Token::get($user['id']);
        // 如果數(shù)據(jù)庫中已存在token,更新
        if ($token) {
            // 刪除舊的緩存
            cache($token['token'], null);
            // 執(zhí)行更新
            $token->isUpdate(true)->save($data);
        }
        // 不存在笆搓,插入
        else {
            $token = new Token();
            $data['create_time'] = ApiBase::_timestamp();
            $token->data($data)->save();
        }
        // 3性湿,將token寫入緩存
        Token::cacheToken($token->getData());
        return $token->getData();
    }

這里主要有3個步驟

  1. 根據(jù)用戶及設(shè)備等信息生成一個唯一的token纬傲,uid用于識別用戶,uuid用于識別設(shè)備肤频,time用于保證唯一叹括。將這些信息序列化后加密并生成md5
  2. 根據(jù)用戶id查詢用戶登錄表,不管用戶原來是否已經(jīng)存在token宵荒,新的token將替換舊的token
  3. 將token寫入緩存汁雷,因為token是每個請求都會解析,如果不使用緩存的話报咳,會導(dǎo)致數(shù)據(jù)庫訪問瓶頸侠讯。

客戶端應(yīng)該保存token,然后在訪問一些需要身份認證的API暑刃,比如修改昵稱厢漩,就需要帶上這個token了,而不需要顯示帶上用戶信息岩臣,比如user_id溜嗜。

解析token

服務(wù)端接收客戶端傳遞的token,需要從中解析出相關(guān)的用戶及設(shè)備信息婿脸。

    public static function getToken($key)
    {
        if (!isset($key)) {
            return null;
        }
        $token = cache($key);
        if ($token) {
            return $token;
        }
        else {
            return Token::findByToken($key);
        }
    }

過程很簡單粱胜,先從緩存中取,如果不存在再從數(shù)據(jù)庫中查詢狐树。所有的請求,服務(wù)端都會執(zhí)行解析token鸿脓。

驗證token

服務(wù)端簡單地把API分為三類

  1. 公共API抑钟,客戶端可以任意訪問,不需要驗證身份野哭,此類API多以GET請求為多在塔。比如查詢產(chǎn)品列表
  2. 受保護的API,也即需要強制認證的API拨黔,這類API需要驗證客戶端身份才能訪問蛔溃,比如修改頭像,客戶端未傳token或token無效篱蝇,服務(wù)端返回一個錯誤碼贺待。
  3. 可選認證的API,介于1和2之間零截,不要求強制驗證客戶端身份麸塞,比如分享獎勵,如果客戶端傳遞了token并認證通過了涧衙,則給相應(yīng)的獎勵哪工,否則不做任何的獎勵奥此。

基于上面的分析,驗證token附帶一個是否強制驗證的參數(shù)雁比,用于中斷稚虎。驗證的規(guī)則也相對簡單,只要用戶請求的設(shè)備ID與token中的設(shè)備ID相同就算驗證通過了偎捎。

    public function checkToken($exit = true)
    {
        if ($this->token) {
            if ($this->token['uuid'] === $this->request->param('uuid', '')) {
                return true;
            } else {
                if ($exit) {
                    $this->logic_failure(null, 'user_offline');
                } else {
                    $this->token = null;
                }
                return false;
            }
        } else {
            if ($exit) {
                $this->logic_failure(null, 'token_invalid');
            }
            return false;
        }
    }

緩存

緩存相對簡單蠢终,緩存的key為加密token之后的md5值,也即登錄成功后鸭限,服務(wù)端向客戶端發(fā)送的token值蜕径。緩存未設(shè)置有效期,默認永不過期败京。

    public static function cacheToken($token)
    {
        if ($token) {
            if (is_object($token)) {
                $token = $token->getData();
            }
            cache($token['token'], ($token));
        }
    }
?>

進階

為了讓您的應(yīng)該更加安全兜喻,還可以在以下方面強化

  1. token有效期
  2. token緩存加密
  3. token高級校驗

不過,我這里已經(jīng)對token做了對稱加密赡麦,相信他人偽造token的可能性也不大朴皆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泛粹,隨后出現(xiàn)的幾起案子遂铡,更是在濱河造成了極大的恐慌,老刑警劉巖晶姊,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扒接,死亡現(xiàn)場離奇詭異,居然都是意外死亡们衙,警方通過查閱死者的電腦和手機钾怔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒙挑,“玉大人宗侦,你說我怎么就攤上這事∫涫矗” “怎么了矾利?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長馋袜。 經(jīng)常有香客問我男旗,道長,這世上最難降的妖魔是什么桃焕? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任剑肯,我火速辦了婚禮,結(jié)果婚禮上观堂,老公的妹妹穿的比我還像新娘让网。我一直安慰自己呀忧,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布溃睹。 她就那樣靜靜地躺著而账,像睡著了一般。 火紅的嫁衣襯著肌膚如雪因篇。 梳的紋絲不亂的頭發(fā)上泞辐,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音竞滓,去河邊找鬼咐吼。 笑死,一個胖子當著我的面吹牛商佑,可吹牛的內(nèi)容都是我干的锯茄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼茶没,長吁一口氣:“原來是場噩夢啊……” “哼肌幽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抓半,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤喂急,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后笛求,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廊移,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年探入,在試婚紗的時候發(fā)現(xiàn)自己被綠了画机。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡新症,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出响禽,到底是詐尸還是另有隱情徒爹,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布芋类,位于F島的核電站隆嗅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏侯繁。R本人自食惡果不足惜胖喳,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贮竟。 院中可真熱鬧丽焊,春花似錦较剃、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至雌贱,卻和暖如春啊送,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欣孤。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工馋没, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人降传。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓篷朵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搬瑰。 傳聞我的和親對象是個殘疾皇子款票,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容