首先了解一下什么是JWT
JWT 是一種開放標準(RFC 7519),用于在各方之間以 JSON 對象形式安全傳輸信息4。其核心特點包括:
結構:由三部分組成(Header、Payload、Signature),通過點號分隔,例如 xxxxx.yyyyy.zzzzz2。Header:聲明加密算法和 Token 類型(如 HS256)。Payload:包含用戶信息、注冊聲明(如 iss、exp)和自定義數據。Signature:通過密鑰對前兩部分簽名,確保數據完整性。
用途:身份認證:用戶登錄后,服務端生成 JWT 返回客戶端,客戶端后續請求攜帶 JWT 以訪問受保護資源1。
JWT的優勢
-
無狀態性
優勢:JWT 自身包含用戶身份和權限信息,服務端無需存儲會話數據(如 Session),直接通過驗證 Token 簽名即可完成認證。 效果:降低服務端資源消耗,天然支持分布式系統和橫向擴展。 對比:傳統 Session 需要服務端維護會話狀態,多服務器場景需共享 Session 存儲(如 Redis),增加復雜度。
-
跨域支持
優勢:JWT 通過 HTTP 頭(如 Authorization: Bearer <token>)傳遞,不受 Cookie 同源策略限制。 應用場景:適合前后端分離、跨域 API 調用及微服務架構。 對比:Cookie 需額外配置 CORS 策略,且存在跨域限制。
-
安全性增強
優勢:防 CSRF:Token 存儲在客戶端而非 Cookie,避免跨站請求偽造攻擊。 防篡改:簽名機制(如 HS256)確保 Token 內容完整性和來源可信。
-
標準化與靈活性
優勢:JWT 遵循 RFC 7519 標準,支持多種簽名算法(如 RSA、HMAC)和自定義聲明(Claims),便于集成第三方服務。 擴展場景:單點登錄(SSO)、API 網關鑒權等。
搭建JWT工具類
首先確定一些參數
private static $key = '4875c029de194dd79ade2ee5aa68ee57';//密鑰
private const exp = 3600;//token過期時間 1小時
private const alg = 'HS256';//加密算法
private const iss = 'ceshi';// 簽發人
private const aud = 'web';// 受眾
密鑰可以自己隨便寫,但是建議不要太簡單
簽發人一般是用于校驗該token是不是自己的
受眾一般是用于區分web和app端的
密鑰可以使用下面代碼生成一個
public function init()
{$md5 = md5(time());return $md5;
}
生成密鑰的方法
public static function createToken($data)
{$time = time();$payload = ["iat" => $time, // 簽發時間"nbf" => $time, // 生效時間"exp" => self::exp + $time, // 失效時間"iss" => self::iss,// 簽發人"aud" => self::aud,// 受眾"data" => $data, // 自定義數據];return JWT::encode($payload, self::$key, self::alg);
}
使用樣例
$token = Token::createToken(['id' => '1', 'role' => 'admin']);
解析密鑰并校驗的方法
解析方法
private static function decodeToken($token)
{try {return JWT::decode($token, new Key(self::$key, self::alg));} catch (\Exception $e) {throw new HttpResponseException(json(['code' => 401, 'msg' => 'token無效']));}
}
驗證管理員
public static function isAdmin($token)
{$decodeToken = self::decodeToken($token);return $decodeToken->data->role === 'admin';
}
使用樣例
if (!Token::isAdmin($token)) {$this->error('權限不足');
}
驗證是否為本人token
public static function checkSelf($userId, $token)
{$decodeToken = self::decodeToken($token);return $decodeToken->data->id == $userId;}
使用樣例
if (!Token::checkSelf($id, $token)) {$this->error('權限不足');
}
完整代碼
<?phpnamespace app\common\library;//這個命名空間記得要換成自己的use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\exception\HttpResponseException;class Token
{private static $key = '4875c029de194dd79ade2ee5aa68ee57';//密鑰private const exp = 3600;//token過期時間 1小時private const alg = 'HS256';//加密算法private const iss = 'ceshi';// 簽發人private const aud = 'web';// 受眾public static function createToken($data){$time = time();$payload = ["iat" => $time, // 簽發時間"nbf" => $time, // 生效時間"exp" => self::exp + $time, // 失效時間"iss" => self::iss,// 簽發人"aud" => self::aud,// 受眾"data" => $data, // 自定義數據];return JWT::encode($payload, self::$key, self::alg);}public static function isAdmin($token){$decodeToken = self::decodeToken($token);return $decodeToken->data->role === 'admin';}public static function checkSelf($userId, $token){$decodeToken = self::decodeToken($token);return $decodeToken->data->id == $userId;}private static function decodeToken($token){try {return JWT::decode($token, new Key(self::$key, self::alg));} catch (\Exception $e) {throw new HttpResponseException(json(['code' => 401, 'msg' => 'token無效']));}}}
使用JWT需要額外安裝擴展
composer require firebase/php-jwt