PHP使用JWT實(shí)現(xiàn)API身份驗(yàn)證的完整流程
1. JWT簡介
JWT由三部分組成:
Header-包含令牌的類型和使用的哈希算法(如HMAC SHA256或RSA)。
Payload-包含聲明(claims)。聲明是關(guān)于實(shí)體(通常是用戶)和其他數(shù)據(jù)的,有三種類型:注冊(cè)聲明、公共聲明和私有聲明。
Signature-對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。
例如,一個(gè)JWT看起來像這樣:`xxxxx.yyyyy.zzzzz`(三個(gè)Base64-URL字符串用點(diǎn)分隔)。
2. 環(huán)境準(zhǔn)備
在開始之前,確保你已經(jīng)安裝了PHP(建議7.4以上版本)和Composer。我們這里使用`firebase/php-jwt`庫來處理JWT的生成和驗(yàn)證。
composer require firebase/php-jwt
3. 用戶注冊(cè)與登錄
3.1 數(shù)據(jù)庫設(shè)計(jì)
為了簡單起見,我們使用MySQL數(shù)據(jù)庫。創(chuàng)建一個(gè)名為users的表:
CREATE TABLE `users` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `username` VARCHAR(50) NOT NULL UNIQUE, `password` VARCHAR(255) NOT NULL );
注意: 密碼必須是經(jīng)過哈希處理,用到的是PHP的password_hash()函數(shù)。
3.2 注冊(cè)接口
在注冊(cè)接口中,我們接收用戶名和密碼,將密碼哈希后存儲(chǔ)到數(shù)據(jù)庫。
<?php
require 'vendor/autoload.php';
use Firebase\JWT\JWT;
// 連接數(shù)據(jù)庫
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
function register($username, $password) {
global $pdo;
// 檢查用戶名是否已存在
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$username]);
if ($stmt->fetch()) {
return ['error' => 'User already exists'];
}
// 哈希密碼
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$username, $hash]);
return ['message' => 'User registered successfully'];
}
3.3 登錄接口
登錄時(shí),驗(yàn)證用戶名和密碼,如果正確,則生成JWT令牌返回給客戶端。
function login($username, $password) {
global $pdo;
$stmt = $pdo->prepare("SELECT id, password FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if (!$user || !password_verify($password, $user['password'])) {
return ['error' => 'Invalid credentials'];
}
// 生成JWT
$secret_key = "your_secret_key"; // 應(yīng)該是一個(gè)復(fù)雜的隨機(jī)字符串,存儲(chǔ)在環(huán)境變量中
$payload = [
'iss' => 'localhost', // 簽發(fā)者
'aud' => 'localhost', // 接收方
'iat' => time(), // 簽發(fā)時(shí)間
'exp' => time() + 3600, // 過期時(shí)間(1小時(shí))
'data' => [
'user_id' => $user['id'],
'username' => $username
]
];
$jwt = JWT::encode($payload, $secret_key, 'HS256');
return ['token' => $jwt];
}
4. 驗(yàn)證JWT
在需要身份驗(yàn)證的API(例如用戶個(gè)人信息接口)中,我們需要驗(yàn)證客戶端傳來的JWT。
function getProfile() {
// 獲取Authorization頭
$headers = getallheaders();
if (!isset($headers['Authorization'])) {
http_response_code(401);
return ['error' => 'Token not provided'];
}
$token = str_replace('Bearer ', '', $headers['Authorization']);
$secret_key = "your_secret_key";
try {
$decoded = JWT::decode($token, new Firebase\JWT\Key($secret_key, 'HS256'));
// 如果驗(yàn)證成功,$decoded將包含我們之前設(shè)置的payload
$user_id = $decoded->data->user_id;
// 現(xiàn)在可以根據(jù)user_id從數(shù)據(jù)庫獲取用戶信息并返回
// ... 數(shù)據(jù)庫查詢代碼 ...
return ['user' => $userInfo];
} catch (Exception $e) {
http_response_code(401);
return ['error' => 'Invalid token'];
}
}
5. 安全性考慮
- 使用HTTPS:在傳輸過程中保護(hù)JWT,防止被截獲。
- 密鑰安全:密鑰(
secret_key)必須足夠復(fù)雜,且不要硬編碼在代碼中,應(yīng)該使用環(huán)境變量。 - 令牌過期:設(shè)置合理的過期時(shí)間(如1小時(shí)),并考慮使用刷新令牌機(jī)制來延長會(huì)話。
- 存儲(chǔ)方式:客戶端通常將JWT存儲(chǔ)在localStorage或sessionStorage中,但要注意XSS攻擊。也可以使用HttpOnly的Cookie來存儲(chǔ),避免XSS,但要注意CSRF防護(hù)。
6. 總結(jié)
通過本文,我們學(xué)習(xí)了如何在PHP中使用JWT進(jìn)行API身份驗(yàn)證。從用戶注冊(cè)登錄到JWT的生成與驗(yàn)證,我們實(shí)現(xiàn)了一套完整的流程。JWT提供了一種無狀態(tài)的認(rèn)證機(jī)制,非常適合分布式應(yīng)用和前后端分離架構(gòu)。當(dāng)然,安全是一個(gè)持續(xù)的過程,除了本文介紹的內(nèi)容,我們平時(shí)開發(fā)的時(shí)候還是需要關(guān)注其他安全措施,比如常見的輸入驗(yàn)證、基礎(chǔ)防止SQL注入等。
以上就是PHP使用JWT實(shí)現(xiàn)API身份驗(yàn)證的完整流程的詳細(xì)內(nèi)容,更多關(guān)于PHP JWT實(shí)現(xiàn)API身份驗(yàn)證的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于PHP結(jié)束標(biāo)簽的使用細(xì)節(jié)探討及聯(lián)想
PHP解析文件時(shí)會(huì)尋找開始?php和結(jié)束標(biāo)記?,標(biāo)記告訴PHP開始和停止解釋其中的代碼,接下來將詳細(xì)介紹下PHP結(jié)束標(biāo)簽的使用細(xì)節(jié)感興趣的你可以參考下本文或許可以幫助到你2013-03-03
PHP與MySQL開發(fā)中頁面出現(xiàn)亂碼的一種解決方法
PHP與MySQL開發(fā)中頁面出現(xiàn)亂碼的一種解決方法...2007-07-07
PHP實(shí)現(xiàn)的自定義數(shù)組排序函數(shù)與排序類示例
這篇文章主要介紹了PHP實(shí)現(xiàn)的自定義數(shù)組排序函數(shù)與排序類,結(jié)合實(shí)例形式分析了php自定義二維數(shù)組排序函數(shù)與排序類的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-11-11
mysql_connect localhost和127.0.0.1的區(qū)別(網(wǎng)絡(luò)層闡述)
這篇文章主要介紹了mysql_connect localhost和127.0.0.1的區(qū)別(網(wǎng)絡(luò)層闡述),本文從網(wǎng)絡(luò)通信層面講解了它們的不同,需要的朋友可以參考下2015-03-03

