php實現(xiàn)jwt

JWT是什么

JWT是json web token縮寫。它將用戶信息加密到token里,服務器不保存任何用戶信息。服務器通過使用保存的密鑰驗證token的正確性盛正,只要正確即通過驗證∩莼耄基于token的身份驗證可以替代傳統(tǒng)的cookie+session身份驗證方法蛮艰。

JWT由三個部分組成:header.payload.signature

以下示例以JWT官網為例

header部分:

{
  "alg": "HS256",
  "typ": "JWT"
}

對應base64UrlEncode編碼為:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
說明:該字段為json格式腋腮。alg字段指定了生成signature的算法雀彼,默認值為 HS256,typ默認值為JWT


payload部分:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

對應base64UrlEncode編碼為:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
說明:該字段為json格式即寡,表明用戶身份的數(shù)據(jù)徊哑,可以自己自定義字段,很靈活聪富。sub 面向的用戶莺丑,name 姓名 ,iat 簽發(fā)時間。例如可自定義示例如下:

{
    "iss": "admin",          //該JWT的簽發(fā)者
    "iat": 1535967430,        //簽發(fā)時間
    "exp": 1535974630,        //過期時間
    "nbf": 1535967430,         //該時間之前不接收處理該Token
    "sub": "www.admin.com",   //面向的用戶
    "jti": "9f10e796726e332cec401c569969e13e"   //該Token唯一標識
}

signature部分:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  123456
) 

對應的簽名為:keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU


最終得到的JWT的Token為(header.payload.signature):eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU
說明:對header和payload進行base64UrlEncode編碼后進行拼接墩蔓。通過key(這里是123456)進行HS256算法簽名梢莽。

JWT使用流程

  1. 初次登錄:用戶初次登錄,輸入用戶名密碼
  2. 密碼驗證:服務器從數(shù)據(jù)庫取出用戶名和密碼進行驗證
  3. 生成JWT:服務器端驗證通過奸披,根據(jù)從數(shù)據(jù)庫返回的信息昏名,以及預設規(guī)則,生成JWT
  4. 返還JWT:服務器的HTTP RESPONSE中將JWT返還
  5. 帶JWT的請求:以后客戶端發(fā)起請求阵面,HTTP REQUEST
  6. HEADER中的Authorizatio字段都要有值轻局,為JWT
  7. 服務器驗證JWT

PHP如何實現(xiàn)JWT

作者使用的是PHP 7.0.31,不廢話样刷,直接上代碼仑扑,新建jwt.php,復制粘貼如下:

<?php
/**
 * PHP實現(xiàn)jwt
 */
class Jwt {

    //頭部
    private static $header=array(
        'alg'=>'HS256', //生成signature的算法
        'typ'=>'JWT'    //類型
    );

    //使用HMAC生成信息摘要時所使用的密鑰
    private static $key='123456';


    /**
     * 獲取jwt token
     * @param array $payload jwt載荷   格式如下非必須
     * [
     *  'iss'=>'jwt_admin',  //該JWT的簽發(fā)者
     *  'iat'=>time(),  //簽發(fā)時間
     *  'exp'=>time()+7200,  //過期時間
     *  'nbf'=>time()+60,  //該時間之前不接收處理該Token
     *  'sub'=>'www.admin.com',  //面向的用戶
     *  'jti'=>md5(uniqid('JWT').time())  //該Token唯一標識
     * ]
     * @return bool|string
     */
    public static function getToken(array $payload)
    {
        if(is_array($payload))
        {
            $base64header=self::base64UrlEncode(json_encode(self::$header,JSON_UNESCAPED_UNICODE));
            $base64payload=self::base64UrlEncode(json_encode($payload,JSON_UNESCAPED_UNICODE));
            $token=$base64header.'.'.$base64payload.'.'.self::signature($base64header.'.'.$base64payload,self::$key,self::$header['alg']);
            return $token;
        }else{
            return false;
        }
    }


    /**
     * 驗證token是否有效,默認驗證exp,nbf,iat時間
     * @param string $Token 需要驗證的token
     * @return bool|string
     */
    public static function verifyToken(string $Token)
    {
        $tokens = explode('.', $Token);
        if (count($tokens) != 3)
            return false;

        list($base64header, $base64payload, $sign) = $tokens;

        //獲取jwt算法
        $base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
        if (empty($base64decodeheader['alg']))
            return false;

        //簽名驗證
        if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decodeheader['alg']) !== $sign)
            return false;

        $payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);

        //簽發(fā)時間大于當前服務器時間驗證失敗
        if (isset($payload['iat']) && $payload['iat'] > time())
            return false;

        //過期時間小宇當前服務器時間驗證失敗
        if (isset($payload['exp']) && $payload['exp'] < time())
            return false;

        //該nbf時間之前不接收處理該Token
        if (isset($payload['nbf']) && $payload['nbf'] > time())
            return false;

        return $payload;
    }




    /**
     * base64UrlEncode   https://jwt.io/  中base64UrlEncode編碼實現(xiàn)
     * @param string $input 需要編碼的字符串
     * @return string
     */
    private static function base64UrlEncode(string $input)
    {
        return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
    }

    /**
     * base64UrlEncode  https://jwt.io/  中base64UrlEncode解碼實現(xiàn)
     * @param string $input 需要解碼的字符串
     * @return bool|string
     */
    private static function base64UrlDecode(string $input)
    {
        $remainder = strlen($input) % 4;
        if ($remainder) {
            $addlen = 4 - $remainder;
            $input .= str_repeat('=', $addlen);
        }
        return base64_decode(strtr($input, '-_', '+/'));
    }

    /**
     * HMACSHA256簽名   https://jwt.io/  中HMACSHA256簽名實現(xiàn)
     * @param string $input 為base64UrlEncode(header).".".base64UrlEncode(payload)
     * @param string $key
     * @param string $alg   算法方式
     * @return mixed
     */
    private static function signature(string $input, string $key, string $alg = 'HS256')
    {
        $alg_config=array(
            'HS256'=>'sha256'
        );
        return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key,true));
    }
}

    //測試和官網是否匹配begin
    $payload=array('sub'=>'1234567890','name'=>'John Doe','iat'=>1516239022);
    $jwt=new Jwt;
    $token=$jwt->getToken($payload);
    echo "<pre>";
    echo $token;
    
    //對token進行驗證簽名
    $getPayload=$jwt->verifyToken($token);
    echo "<br><br>";
    var_dump($getPayload);
    echo "<br><br>";
    //測試和官網是否匹配end
    
    
    //自己使用測試begin
    $payload_test=array('iss'=>'admin','iat'=>time(),'exp'=>time()+7200,'nbf'=>time(),'sub'=>'www.admin.com','jti'=>md5(uniqid('JWT').time()));;
    $token_test=Jwt::getToken($payload_test);
    echo "<pre>";
    echo $token_test;
    
    //對token進行驗證簽名
    $getPayload_test=Jwt::verifyToken($token_test);
    echo "<br><br>";
    var_dump($getPayload_test);
    echo "<br><br>";
    //自己使用時候end
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末置鼻,一起剝皮案震驚了整個濱河市镇饮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箕母,老刑警劉巖储藐,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梅肤,死亡現(xiàn)場離奇詭異,居然都是意外死亡邑茄,警方通過查閱死者的電腦和手機姨蝴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肺缕,“玉大人左医,你說我怎么就攤上這事⊥荆” “怎么了浮梢?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長彤路。 經常有香客問我秕硝,道長,這世上最難降的妖魔是什么洲尊? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任远豺,我火速辦了婚禮,結果婚禮上坞嘀,老公的妹妹穿的比我還像新娘躯护。我一直安慰自己,他們只是感情好丽涩,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布棺滞。 她就那樣靜靜地躺著,像睡著了一般矢渊。 火紅的嫁衣襯著肌膚如雪继准。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天矮男,我揣著相機與錄音移必,去河邊找鬼。 笑死昂灵,一個胖子當著我的面吹牛避凝,可吹牛的內容都是我干的。 我是一名探鬼主播眨补,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼癌蚁,長吁一口氣:“原來是場噩夢啊……” “哼尊浓!你這毒婦竟也來了拄踪?” 一聲冷哼從身側響起城瞎,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后含潘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饲做,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年遏弱,在試婚紗的時候發(fā)現(xiàn)自己被綠了盆均。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡漱逸,死狀恐怖泪姨,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情饰抒,我是刑警寧澤肮砾,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站袋坑,受9級特大地震影響仗处,放射性物質發(fā)生泄漏。R本人自食惡果不足惜枣宫,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一婆誓、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镶柱,春花似錦旷档、人聲如沸模叙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽范咨。三九已至故觅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渠啊,已是汗流浹背输吏。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留替蛉,地道東北人贯溅。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像躲查,于是被迫代替她去往敵國和親它浅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容