JSON Web Token 的理解,以及在 PHP 中的使用

  • 阮一峰-JSON Web Token 入門教程

  • JSON Web Token - 在Web應用間安全地傳遞信息

  • 八幅漫畫理解使用JSON Web Token設(shè)計單點登錄系統(tǒng)

  • 使用場景
    json web token 的介紹,網(wǎng)上有很多資料,就不詳細解釋了。我個人說下對它的理解和應用場景。很多資料喜歡解釋它的一個應用場景是,比如在簡書上,有人關(guān)注你了,會給你郵箱發(fā)送一個鏈接,然后登陸到簡書網(wǎng)站上取查看關(guān)注者。這種情況下,如果你沒有登陸網(wǎng)站,就需要自己先登陸。如果使用JWT,則就不需要你在登陸了。通過這個場景,我來說下認證用戶這方面

  • 原理
    認證用戶一般在網(wǎng)站上是賬號密碼登陸,存入session。 很多App 接口還是先請求登陸接口,然后獲取到 token,再去請求登陸后的操作。所以,不管是 session 還是 JWT,都是解決用戶認證的問題。這兩種方式,本質(zhì)上都是通過一個 token,也就是不能讓外人知道的值,來驗證這條請求的合法性,因為理論上只有你自己的客戶端才知道你的 token。
    JWT 也是如此,只要服務(wù)端根據(jù)客戶的請求數(shù)據(jù),驗證 token 值一致,就能夠證明數(shù)據(jù)是正常渠道來的。因為加密的時候加密方式和加密的 key 值是只有你們自己才有的。如果需要什么數(shù)據(jù),你直接再 post 或者 get 中加入自己的鍵值對即可。

  • JWT 的優(yōu)勢

一、token 值可以直接根據(jù)加密跟則加密比對,不需要查詢數(shù)據(jù)庫。減少服務(wù)器壓力。即使是 session 存儲,也會占用服務(wù)器內(nèi)存
二、payload 值可以自定義這條請求數(shù)據(jù)的有效時間(exp 字段),防止別人得到token后利用
三、hash 或者 rsa 加密,同樣的數(shù)據(jù),每次加密的值都是不同的,也就是token 值可變,提高了數(shù)據(jù)的安全性,但是登陸請求的那種,基本上 token 是固定的。
四、加密時候有個 key 值或者rsa加密的公私鑰,是只有自己的服務(wù)端和客戶端才知道的,只要這個值不泄露,加密比對就不會有誤
五、JWT方式將用戶狀態(tài)分散到了客戶端中,可以明顯減輕服務(wù)端的內(nèi)存壓力。除了用戶id之外,還可以存儲其他的和用戶相關(guān)的信息,例如該用戶是否是管理員、用戶所在的分層

數(shù)據(jù)庫 token 加密的原理

一般的APP 接口中,都會先登錄,然后返回給你 user_id 和 token 等用戶信息。但是你請求登錄后的接口時,一般會帶上這兩個參數(shù)。token 一般有個過期時間。token 可以理解成可以被外人捕捉到的密碼,因為他會過期,所以即使別人抓取到了,token 會有過期時間,也比抓取到密碼強。
其實傳遞 token 就可以獲取到用戶數(shù)據(jù),根本不需要傳遞 user_id 。之所以傳遞 user_id , 是因為查詢的時候,使用 user_id 查詢會快,然后比對 user_id 對應的 token ,與請求的 token 是否匹配。但是直接比對 token ,也是可以的。 因為token 是唯一值,跟密碼不一樣。比如是在使用 TeamView 找回密碼時,人家就是直接帶了 token 值。你點擊就是直接登錄的狀態(tài)。
但是 JWT 的token 與 數(shù)據(jù)庫的這種 token 不一樣,JWT token 是認證這條數(shù)據(jù)的合法性,也就是你這個 token 只要匹配了,你就是正常的用戶請求,可以做任何操作,都是安全的。但是數(shù)據(jù)庫的這種 token 是你數(shù)據(jù)庫中的一個固定值,是認證用戶用的。

圖片.png
  • index.php 生成加密數(shù)據(jù)
<?php


define('HASH_KEY', 123456);// 自定義 hash 加密得 key

// header 部分
$head_json = '{
  "typ": "JWT",
  "alg": "SHA256"
}';
$head = base64_encode($head_json);

// payload 部分
$payload = '{
    "iss": "John Wu JWT",
    "iat": 1441593502,
    "exp": 144159472211,
    "aud": "www.example.com",
    "sub": "jrocket@example.com",
    "from_user": "B",
    "target_user": "A"
}';

$payload = base64_encode($payload);

// signature
$sign = hash_hmac(strtolower((json_decode($head_json, true))['alg']), $head . $payload, HASH_KEY);

echo $head;
echo '<hr>';
echo $payload;
echo '<hr>';
echo $sign;

echo '<hr>';
echo $head . '.' . $payload . '.' . $sign;
image.png
  • server.php 中譚政 token ,獲取數(shù)據(jù)
<?php

define('HASH_KEY', 123456);// 自定義 hash 加密得 key

/**
 *  獲取頭部的 token
 */
function getBearerToken()
{
    if (!isset($_SERVER['HTTP_' . strtoupper('Authorization')])) {
        return false; // 頭部不存在 Authorization
    }
    $auth = $_SERVER['HTTP_' . strtoupper('Authorization')];

    if (substr($auth, 0, strlen('Bearer ')) !== 'Bearer ') {
        return false; // token 不存在
    }
    $token = substr($auth, 7); // Bearer 字符串和空格之后的字符串,是從7開始的
    return $token;
}

$token = getBearerToken();
// 1. 檢測 token 值
if (!$token) {
    echo '清閑登陸';
}

list($head, $body, $sign) = explode('.', $token);
$head_info = json_decode(base64_decode($head), true);
$body_info = json_decode(base64_decode($body), true);

// 2.檢測 信息是否過去
if ($body_info['exp'] <= time()) {
    echo 'token 已經(jīng)過期';
}


$algo = $head_info['alg'];
$hash = hash_hmac(strtolower($algo), $head . $body, HASH_KEY);
$verify = hash_equals($sign, $hash);

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

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

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