基於JWT的Token登錄認證


1.JWT簡介

        JSON Web Token(縮寫 JWT),是目前最流行的跨域認證解決方案。

2.JWT的原理

       JWT的原理是,服務器認證以后,生成一個JSON格式的對象,發回給客戶端,就像下面這樣.

 

{
  "用戶名": "admin",
  "角色": "超級管理員",
  "到期時間": "2019-07-13 00:00:00"
}

 

          以后,客戶端與服務端通信的時候,都要發回這個 JSON 對象。服務器完全只靠這個對象認定用戶身份。

       為了防止用戶篡改數據,服務器在生成這個對象的時候,會加上簽名(詳見后文)。

        服務器不再保存任何 session 數據,也就是服務器變成無狀態了,從而比較容易實現擴展。

3.JWT的數據結構

        實際的 JWT是一個很長的字符串,中間用點(.)分隔成三個部分。 就像下面這樣:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjNmMmc1N2E5MmFhIn0.eyJpYXQiOjE1NjI4MzM0MDgsImlzcyI6Imh0dHA6XC9cL3d3dy5weWcuY29tIiwiYXVkIjoiaHR0cDpcL1wvd3d3LnB5Zy5jb20iLCJuYmYiOjE1NjI4MzM0MDcsImV4cCI6MTU2MjkxOTgwOCwianRpIjoiM2YyZzU3YTkyYWEiLCJ1c2VyX2lkIjoxfQ.NFq1qQ-Z5c4pwit8ZkyWEwX6SBXmnHJcc6ZDgSD5nhU

          JWT的三個部分依次如下:

- Header(頭部)
- Payload(負載)
- Signature(簽名)

4.JWT的使用方式

             客戶端收到服務器返回的 JWT,可以儲存在 Cookie 里面,也可以儲存在 localStorage。

此后,客戶端每次與服務器通信,都要帶上這個 JWT。你可以把它放在 Cookie 里面自動發送,但是這樣不能跨域,所以更好的做法是放在 HTTP 請求的頭信息Authorization字段里面

5.JWT的幾個特點

          (1)JWT 默認是不加密,但也是可以加密的。生成原始 Token 以后,可以用密鑰再加密一次。

           (2)JWT 不加密的情況下,不能將秘密數據寫入 JWT。

           (3)JWT 不僅可以用於認證,也可以用於交換信息。有效使用 JWT,可以降低服務器查詢數據庫的次數。

           (4)JWT 的最大缺點是,由於服務器不保存 session 狀態,因此無法在使用過程中廢止某個 token,或者更改 token 的權限。也就是說,一旦 JWT 簽發了,在到期之前就會始終有效,除非服務器部署額外的邏輯。

           (5)JWT 本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限。為了減少盜用,JWT 的有效期應該設置得比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。

           (6)為了減少盜用,JWT 不應該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸。

6.JWT功能實現

             使用composer安裝 JWT 功能組件

composer require lcobucci/jwt 3.3
<?php
namespace tools\jwt;

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\ValidationData;

/**
 * Created by PhpStorm.
 * User: asus
 * Date: 2019/4/5
 * Time: 13:02
 */
class Token
{
    private static $_config = [
        'audience' => '',//接收人
        'id' => '',//token的唯一標識,這里只是一個簡單示例
        'sign' => '',//簽名密鑰
        'issuer' => '',//簽發人
        'expire' => 3600*24 //有效期
    ];

    //生成token
    public static function getToken($user_id){

        //簽名對象
        $signer = new Sha256();
        //獲取當前時間戳
        $time = time();
        //設置簽發人、接收人、唯一標識、簽發時間、立即生效、過期時間、用戶id、簽名
        $token = (new Builder())->issuedBy(self::$_config['issuer'])
            ->canOnlyBeUsedBy(self::$_config['audience'])
            ->identifiedBy(self::$_config['id'], true)
            ->issuedAt($time)
            ->canOnlyBeUsedAfter($time-1)
            ->expiresAt($time + self::$_config['expire'])
            ->with('user_id', $user_id)
            ->sign($signer, self::$_config['sign'])
            ->getToken();
        return (string)$token;
    }

    //從請求信息中獲取token令牌
    public static function getRequestToken()
    {
        if (empty($_SERVER['HTTP_AUTHORIZATION'])) {
            return false;
        }

        $header = $_SERVER['HTTP_AUTHORIZATION'];
        $method = 'bearer';
        //去除token中可能存在的bearer標識
        return trim(str_ireplace($method, '', $header));
    }

    //從token中獲取用戶id (包含token的校驗)
    public static function getUserId($token = null)
    {
        $user_id = null;

        $token = empty($token)?self::getRequestToken():$token;

        if (!empty($token)) {
            //為了注銷token 加以下if判斷代碼
            $delete_token = cache('delete_token') ?: [];
            if(in_array($token, $delete_token)){
                //token已被刪除(注銷)
                return $user_id;
            }
            $token = (new Parser())->parse((string) $token);
            //驗證token
            $data = new ValidationData();
            $data->setIssuer(self::$_config['issuer']);//驗證的簽發人
            $data->setAudience(self::$_config['audience']);//驗證的接收人
            $data->setId(self::$_config['id']);//驗證token標識

            if (!$token->validate($data)) {
                //token驗證失敗
                return $user_id;
            }

            //驗證簽名
            $signer = new Sha256();
            if (!$token->verify($signer, self::$_config['sign'])) {
                //簽名驗證失敗
                return $user_id;
            }
            //從token中獲取用戶id
            $user_id = $token->getClaim('user_id');
        }

        return $user_id;
    }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM