JSON Web Token 的理解

小龍發表於2019-03-23

推薦閱讀

json web token 的介紹,網上有很多資料,就不詳細解釋了。我個人說下對它的理解和應用場景。很多資料喜歡解釋它的一個應用場景是,比如在簡書上,有人關注你了,會給你郵箱傳送一個連結,然後登陸到簡書網站上取檢視關注者。這種情況下,如果你沒有登陸網站,就需要自己先登陸。如果使用JWT,則就不需要你在登陸了。通過這個場景,我來說下認證使用者這方面

  • 原理

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

  • JWT 的優勢

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

  • index.php 生成加密資料
<?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;

1

  • server.php 中譚政 token ,獲取資料
    <?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 已經過期';
    }
    $algo = $head_info['alg'];
    $hash = hash_hmac(strtolower($algo), $head . $body, HASH_KEY);
    $verify = hash_equals($sign, $hash);
    echo $verify;

    1

相關文章