基于PHP實現(xiàn)JWT登錄鑒權(quán)的示例代碼
一、什么是JWT
1、簡介
JWT(JSON Web Token)是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)。
簡單的說,JWT就是一種Token的編碼算法,服務(wù)器端負(fù)責(zé)根據(jù)一個密碼和算法生成Token,然后發(fā)給客戶端,客戶端只負(fù)責(zé)后面每次請求都在HTTP header里面帶上這個Token,服務(wù)器負(fù)責(zé)驗證這個Token是不是合法的,有沒有過期等,并可以解析出subject和claim里面的數(shù)據(jù)。
2、JWT的組成
第一部分為頭部(header),第二部分我們稱其為載荷(payload),第三部分是簽證(signature)?!局虚g用 . 分隔】
一個標(biāo)準(zhǔn)的JWT生成的token格式如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjRmMWcyM2ExMmFhMTEifQ.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUub3JnIiwianRpIjoiNGYxZzIzYTEyYWExMSIsImlhdCI6MTY0MDE3MTA1MywibmJmIjoxNjQwMTcxMDU0LCJleHAiOjE2NDAxNzQ2NTMsInVpZCI6MjAsInVzZXJuYW1lIjoiTWFrZSJ9.bysUwNIyhqqEyL0JecSHdplSTfE6G6zuCsrAn6eyrQM
使用https://jwt.io/這個網(wǎng)站對JWT Token進行解析的結(jié)果如下

3、JWT驗證流程和特點
驗證流程:
① 在頭部信息中聲明加密算法和常量, 然后把header使用json轉(zhuǎn)化為字符串
② 在載荷中聲明用戶信息,同時還有一些其他的內(nèi)容;再次使用json 把載荷部分進行轉(zhuǎn)化,轉(zhuǎn)化為字符串
③ 使用在header中聲明的加密算法和每個項目隨機生成的secret來進行加密, 把第一步分字符串和第二部分的字符串進行加密, 生成新的字符串。詞字符串是獨一無二的。
④ 解密的時候,只要客戶端帶著JWT來發(fā)起請求,服務(wù)端就直接使用secret進行解密。
特點:
① 三部分組成,每一部分都進行字符串的轉(zhuǎn)化
② 解密的時候沒有使用數(shù)據(jù)庫,僅僅使用的是secret進行解密
③ JWT的secret千萬不能泄密!
④ 不依賴數(shù)據(jù)庫,而是直接根據(jù)token取出保存的用戶信息,以及對token可用性校驗,校驗方式更加簡單便捷化,單點登錄更為簡單。
二、相關(guān)問題
- JWT Token需要持久化在redis、Memcached中嗎?
不應(yīng)該這樣做,無狀態(tài)的jwt變成了有狀態(tài)了,背離了JWT通過算法驗證的初心。
- 在退出登錄時怎樣實現(xiàn)JWT Token失效呢?
退出登錄, 只要客戶端端把Token丟棄就可以了,服務(wù)器端不需要廢棄Token。
- 怎樣保持客戶端長時間保持登錄狀態(tài)?
服務(wù)器端提供刷新Token的接口, 客戶端負(fù)責(zé)按一定的邏輯刷新服務(wù)器Token。
三、PHP實現(xiàn)
1、引入依賴
composer require lcobucci/jwt 3.*
2、功能實現(xiàn)
- 簽發(fā)token, 設(shè)置簽發(fā)人、接收人、唯一標(biāo)識、簽發(fā)時間、立即生效、過期時間、用戶id、用戶username、簽名。其中,用戶id、用戶username是特意存儲在token中的信息,也可以增加一些其他信息,這樣在解析的時候就可以直接獲取到這些信息,不能是敏感數(shù)據(jù)
- 驗證令牌驗證這個Token是不是合法的,有沒有過期等,并可以解析出subject和claim里面的數(shù)據(jù),傳遞jwt token的方式為Authorization中的Bearer Token,如下

3、封裝工具類如下
<?php
/**
* Created by PhpStorm
* @author sxd
*/
namespace App\Utils;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\JWT\Token\Plain;
use Lcobucci\JWT\Validation\Constraint\IdentifiedBy;
use Lcobucci\JWT\Validation\Constraint\IssuedBy;
use Lcobucci\JWT\Validation\Constraint\PermittedFor;
use Lcobucci\JWT\ValidationData;
class JwtUtil
{
// jwt github: https://github.com/lcobucci/jwt https://jwt.io/
protected $issuer = "http://example.com";
protected $audience = "http://example.org";
protected $id = "4f1g23a12aa11";
// key 是絕對不允許泄露的
protected static $key = "8swQsm1Xb0TA0Jw5ASPwClKVZPoTyS7GvhtaW0MxzKEihs1BNpcS2q3FYMJ11111";
/**
* 簽發(fā)令牌
*/
public function getToken()
{
$time = time();
$config = self::getConfig();
assert($config instanceof Configuration);
// 簽發(fā)token, 設(shè)置簽發(fā)人、接收人、唯一標(biāo)識、簽發(fā)時間、立即生效、過期時間、用戶id、用戶username、簽名
$token = $config->builder()
->issuedBy($this->issuer) // Configures the issuer (iss claim)
->permittedFor($this->audience) // Configures the audience (aud claim)
->identifiedBy($this->id, true) // Configures the id (jti claim), replicating as a header item
->issuedAt($time) // Configures the time that the token was issue (iat claim)
->canOnlyBeUsedAfter($time + 1) // Configures the time that the token can be used (nbf claim) 簽發(fā)x秒鐘后生效
->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
->withClaim('uid', 20) // Configures a new claim, called "uid"
->withClaim('username', "Make") // Configures a new claim, called "uid"
->getToken($config->signer(), $config->signingKey()); // Retrieves the generated token
return $token->toString();
}
/**
* 驗證 jwt token 并返回其中的用戶id
* verify token
*/
public function verifyToken_bak($token)
{
try {
$config = self::getConfig();
assert($config instanceof Configuration);
$token = $config->parser()->parse($token);
assert($token instanceof Plain);
//Lcobucci\JWT\Validation\Constraint\IdentifiedBy: 驗證jwt id是否匹配
//Lcobucci\JWT\Validation\Constraint\IssuedBy: 驗證簽發(fā)人參數(shù)是否匹配
//Lcobucci\JWT\Validation\Constraint\PermittedFor: 驗證受眾人參數(shù)是否匹配
//Lcobucci\JWT\Validation\Constraint\RelatedTo: 驗證自定義cliam參數(shù)是否匹配
//Lcobucci\JWT\Validation\Constraint\SignedWith: 驗證令牌是否已使用預(yù)期的簽名者和密鑰簽名
//Lcobucci\JWT\Validation\Constraint\StrictValidAt: ::驗證存在及其有效性的權(quán)利要求中的iat,nbf和exp(支持余地配置
//Lcobucci\JWT\Validation\Constraint\LooseValidAt: 驗證的權(quán)利要求iat,nbf和exp,當(dāng)存在時(支持余地配置)
//驗證jwt id是否匹配
$validate_jwt_id = new IdentifiedBy($this->id);
//驗證簽發(fā)人url是否正確
$validate_issued = new IssuedBy($this->issuer);
//驗證客戶端url是否匹配
$validate_aud = new PermittedFor($this->audience);
$config->setValidationConstraints($validate_jwt_id, $validate_issued, $validate_aud);
$constraints = $config->validationConstraints();
if (!$config->validator()->validate($token, ...$constraints)) {
die("token invalid!");
}
} catch (\Exception $e) {
die("error:" . $e->getMessage());
}
$jwtInfo = $token->claims(); // 這是jwt token中存儲的所有信息
return $jwtInfo->get("uid"); // 獲取uid
}
/**
* 加密解密使用的配置
* @return Configuration
*/
public static function getConfig()
{
$configuration = Configuration::forSymmetricSigner(
// You may use any HMAC variations (256, 384, and 512)
new Sha256(),
// replace the value below with a key of your own!
InMemory::base64Encoded(self::$key)
// You may also override the JOSE encoder/decoder if needed by providing extra arguments here
);
return $configuration;
}
/**
* 另一種驗證方法,但是已經(jīng)棄用
* verify token
*/
public function verifyToken($token)
{
$token = (new Parser())->parse((string)$token);
//驗證token
$data = new ValidationData();
$data->setIssuer($this->issuer);//驗證的簽發(fā)人
$data->setAudience($this->audience);//驗證的接收人
$data->setId($this->id);//驗證token標(biāo)識
if (!$token->validate($data)) {
//token驗證失敗
die("token invalid!");
}
$jwtInfo = $token->claims(); // 這是jwt token中存儲的所有信息
return $jwtInfo->get("uid"); // 獲取uid
}
}
以上就是基于PHP實現(xiàn)JWT登錄鑒權(quán)的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于PHP JWT登錄鑒權(quán)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PHP基于PDO調(diào)用sqlserver存儲過程通用方法【基于Yii框架】
這篇文章主要介紹了PHP基于PDO調(diào)用sqlserver存儲過程通用方法,結(jié)合實例形式分析了基于Yii框架采用pdo調(diào)用sqlserver存儲過程的相關(guān)操作步驟與實現(xiàn)技巧,需要的朋友可以參考下2017-10-10
php實現(xiàn)動態(tài)口令認(rèn)證的示例代碼
這篇文章主要為大家詳細(xì)介紹了php實現(xiàn)動態(tài)口令認(rèn)證的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
php5.2的curl-bug 服務(wù)器被php進程卡死問題排查
這篇文章主要介紹了php5.2的curl-bug 服務(wù)器被php進程卡死問題排查,需要的朋友可以參考下2016-09-09
奉獻出一個封裝的curl函數(shù) 便于調(diào)用(抓數(shù)據(jù)專用)
這個函數(shù)就是封裝了curl函數(shù)的常用步驟,方便大家抓數(shù)據(jù),小偷程序也是用類似的代碼,需要的朋友可以參考下2013-07-07
php access 數(shù)據(jù)連接與讀取保存編輯數(shù)據(jù)的實現(xiàn)代碼
腳本之家會給出一個php+access的留言本源碼,大家可以參考下。基本上對php access的操作就熟悉了。2010-05-05

