JSON Web Token 使用詳解

JWT是什麼?

JSON Web Token(縮寫 JWT)是目前最流行的<font color='red'>跨域</font>認證解決方案。它是有三部分組成,示例以下,具體的講解以下(jwt是不會有空行的,下面只是爲了顯示,便使用了換行看着比較方便)。php

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjMfQ.

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

它是由一個"."號隔開、三部分組成。
第一部分是header信息,redis

{
  "alg": "HS256",// 加密的算法
  "typ": "JWT"// 加密的方式,填寫JWT
}

第二部分是Payload,有固定的六個部分和自定義數據組成,自定義數據看本身的狀況須要來定義,是能夠省去的。算法

'iss' => 'https://www.qqdeveloper.com',// 簽發人
'exp' => time() + 86400,// 過時時間(這裏的有效期時間爲1天)
'sub' => '主題內容',// 主題
'aud' => '受衆內容',// 受衆
'nbf' => $time,// 生效時間
'iat' => $time,// 簽發時間
'jti' => 123,// 編號

第三部分是Signature(是對前兩部分加密得來的)。因爲前兩部分是公開透明的數據,所以防止數據的篡改和泄露,咱們須要加密處理。首先,須要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。而後,使用 Header 裏面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。shell

第一部分的加密方式(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

最終生成的就是上面很長的一段字符串了。數據庫

爲何會使用JWT

這就須要從咱們傳統的認證模式來講了,傳統的認證模式是基於session和cookie來實現用戶的認證和鑑權。具體的流程模式以下圖。

<center>(圖一)Session與Cookie認證與鑑權</center>
1.客戶端向服務端發送一個http請求。編程

2.服務端在收到客戶端的請求時,生成一個惟一的sessionid,<font color='red'>這裏須要將該生成的session存儲在服務端</font>,這個sessionid存儲具體的session內容,默認的是文件存儲,固然咱們能夠修改具體的存儲方式,例如數據庫存儲。
3.客戶端在接受到這個sessionid時,存在cookie裏面,每次請求時攜帶該sessionid。
4.服務端在接收到客戶端的請求以後,根據客戶端發送的sessionid來進行認證與受權。
這裏也推薦一下本身以前分享的一篇有關session於cookie的知識點。session與cookie詳解
圖片描述
<center>(圖二)傳統的token受權</center>
1.客戶端向服務端發送一個http請求。json

2.服務端在收到客戶端的請求以後,生成一個惟一token,<font color='red'>這裏須要將該生成的token存儲在服務端</font>,至於怎麼存,能夠和上面session與cookie的方式一致。也能夠存在緩存數據庫中,如redis,memcached。
3.服務端將該token返回給客戶端,客戶端存在本地,能夠存請求頭header中,也能夠存在cookie中,同時也能夠存在localstorage中。
4.向服務端發送請求時,攜帶該token,服務端進行認證或者受權。
圖片描述
<center>(圖三)JWT認證模式</center>
1.客戶端向服務端發送一個http請求。跨域

2.服務端根據jwt的生成規則,生成一個token,並返回給客戶端,<font color='red'>這裏服務端是不須要存儲的</font>。
3.客戶端在接受到該token時,存在客戶端。
4.客戶端向服務端發送請求時,服務端對請求的token進行解析,若是發現解析出來的數據和生成的數據是一致的表明是一個合法的token,則進行相應的操做。緩存

基於session和cookie的認證和鑑權模式有什麼好與很差的地方呢?總結以下幾點:

經過上面幾張圖,咱們也大體能夠看得出來,基於session都是須要服務端存儲的,而JWT是不須要服務端來存儲的。針對以上幾點,總結以下:
1、缺點
1.容易遇到跨域問題。不一樣域名下是沒法經過session直接來作到認證和鑑權的。
2.分佈式部署的系統,須要使用共享session機制
3.容易出現csrf問題。安全

2、優勢
1.方便靈活,服務器端直接建立一個sessionid,下發給客戶端,客戶端請求攜帶sessionid便可。
2.session存儲在服務端,更加安全。
3.便於服務端清除session,讓用戶從新受權一次。

JWT與session有什麼區別呢?

JWT是基於客戶端存儲的一種認證方式,然而session是基於服務端存儲的一種認證方式。JWT雖然不用服務端存儲了,也能夠避免跨域、csrf等狀況。但也存在以下幾個不太好的地方。
1.沒法清除認證token。因爲JWT生成的token都是存儲在客戶端的,不能有服務端去主動清除,只有直到失效時間到了才能清除。除非服務端的邏輯作了改變。
2.存儲在客戶端,相對服務端,安全性更低一些。當JWT生成的token被破解,咱們不便於清除該token。

如何使用JWT

這裏推薦使用GitHub上面人家封裝好的包,這裏我使用的是firebase/php-jwt,在項目中直接使用便可安裝成功。

composer require firebase/php-jwt

接下來建立一個控制器,我這裏使用的ThinkPHP5.1的框架

use think\Controller;
use Firebase\JWT\JWT;

class Test extends Controller
{
    private $key = 'jwtKey';

    // 生成JWT
    public function createJwt()
    {
        $time  = time();
        $key   = $this->key;
        $token = [
            'iss' => 'https://www.qqdeveloper.com',// 簽發人
            'exp' => $time + 86400,// 過時時間(這裏的有效期時間爲1天)
            'sub' => '主題內容',// 主題
            'aud' => '受衆內容',// 受衆
            'nbf' => $time,// 生效時間
            'iat' => $time,// 簽發時間
            'jti' => 123,// 編號
            // 額外自定義的數據
            'data' => [
                'userName' => '編程浪子走四方'
            ]];
        // 調用生成加密方法('Payloadn內容','加密的鍵',['加密算法'],['加密的能夠'],['JWT的header頭'])
        $jwt = JWT::encode($token, $key);
        return json(['data' => $jwt]);
    }

    // 解析JWT
    public function analysisJwt()
    {
        try {
            $key = $this->key;
            $jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImV4cCI6MTU2ODA5NjE4MCwic3ViIjoiXHU0ZTNiXHU5ODk4XHU1MTg1XHU1YmI5IiwiYXVkIjoiXHU1M2Q3XHU0ZjE3XHU1MTg1XHU1YmI5IiwibmJmIjoxNTY4MDA5NzgwLCJpYXQiOjE1NjgwMDk3ODAsImp0aSI6MTIzLCJkYXRhIjp7InVzZXJOYW1lIjoiXHU3ZjE2XHU3YTBiXHU2ZDZhXHU1YjUwXHU4ZDcwXHU1NmRiXHU2NWI5In19.kHb_9Np0zjE25YE9czUEGvmFPYtqMJT9tuZzJTuMZl0';
            // 調用解密方法('JWT內容','解密的鍵,和加密時的加密鍵一直','加密算法')
            $decoded = JWT::decode($jwt, $key, array('HS256'));
            return json(['message' => $decoded]);
        } catch (\Exception $exception) {
            return json(['message' => $exception->getMessage()]);
        }

    }
}

經過訪問第一個方法,能夠生成下圖一段字符串
圖片描述
咱們將上圖中的字符串複製到第二圖中的$jwt變量,訪問第二個方法便可解析出具體的數據。
圖片描述

文章來源

圖片描述

相關文章
相關標籤/搜索