推薦閱讀
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;
- 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;