jwt 是什麼?
Json web token (JWT)
, 是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準((RFC 7519).該 token 被設計為緊湊且安全的,特別適用於分散式站點的單點登入(SSO
)場景。JWT
的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的使用者身份資訊,以便於從資源伺服器獲取資源,也可以增加一些額外的其它業務邏輯所必須的宣告資訊,該token也可直接被用於認證,也可被加密。
為什麼不使用 session,而直接使用jwt?
session
儲存在伺服器端,而Jwt
儲存在客戶端。session
方式儲存使用者資訊的最大問題在於要佔用伺服器記憶體,增加伺服器的開銷,而Jwt
方式將使用者狀態分散到了客戶端中,可以明顯減輕伺服器的記憶體壓力。
如何使用
1、composer
安裝
composer require tymon/jwt-auth
2、註冊服務提供者,laravel
框架版本小於5.4時,需要手動在 config/app.php
檔案中註冊服務提供者
'providers' => [
...
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
3、生成配置檔案,執行以下命令
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
4、生成 jwt
金鑰
php artisan jwt:secret
你也可以在 .env
檔案中修改金鑰,比如 JWT_SECRET=xxxx
5、修改 auth.php
檔案中的配置,修改 Laravel
框架預設的 auth
驅動
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User\User::class
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
上述配置,表示 auth
驅動使用 jwt
的方式,使用者提供者使用 users
,使用者提供者支援 database
和 eloquent
兩種方式
6、修改 User
模型,實現 getJWTIdentifier()
和 getJWTCustomClaims()
方法
<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
// Rest omitted for brevity
/**
* Get the identifier that will be stored in the subject claim of the JWT.
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
7、新增控制器認證中介軟體
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
上述程式碼表示,每次請求都需要經過 auth
這個中介軟體,登入方法除外
常用方法
官方文件寫的很清楚,這裡直接給出官方的說明文件,地址如下:
原始碼解析 (重點)
這裡會對原始碼進行分析,預設你瞭解一些基本的知識和框架的執行流程,比如容器、依賴注入、門面模式和中介軟體等知識,這裡不會對這些知識和內容進行過多的闡述,如果有不懂和不理解的地方,歡迎評論,大家系好安全帶,老司機要發車了!!!
使用者鑑權
當訪問控制器中某個方法時,會先經過 Authenticate
中介軟體進行處理
//1.1 經過 handle 方法處理請求
public function handle($request, Closure $next, ...$guards)
{
$this->authenticate($request, $guards);
return $next($request);
}
//1.2 經過 authenticate 方法檢查使用者是否登入
protected function authenticate($request, array $guards)
{
if (empty($guards)) {
$guards = [null];
}
foreach ($guards as $guard) {
// 訪問 JwtGuard 中的 check 方法
if ($this->auth->guard($guard)->check()) { // $this->auth->guard($guard) 會生成JwtGuard物件
return $this->auth->shouldUse($guard);
}
}
$this->unauthenticated($request, $guards);
}
//1.3 訪問程式碼塊 GuardHelpers 中的 check 方法,校驗使用者是否登入
public function check()
{
return ! is_null($this->user());
}
//1.4 訪問 JwtGuard 中的 user 方法
public function user()
{
if ($this->user !== null) {
return $this->user;
}
//獲取請求頭中的 token,校驗 token 是否過期或者在黑名單中,具體的程式碼請檢視原始碼
if ($this->jwt->setRequest($this->request)->getToken() &&
($payload = $this->jwt->check(true)) &&
$this->validateSubject()
) {
//根據負載 payload 獲取使用者的資訊,然後返回
return $this->user = $this->provider->retrieveById($payload['sub']);
}
}
//1.5 建立使用者模型,根據主鍵獲取使用者資訊並且返回
public function retrieveById($identifier)
{
$model = $this->createModel();
return $this->newModelQuery($model)
->where($model->getAuthIdentifierName(), $identifier)
->first();
}
至此,使用者鑑權的核心流程就分析完畢了,這裡只給出了核心程式碼,需要大家根據上述程式碼去檢視原始碼,只有知其然知其所以然,才可以放心大膽的使用擴充套件包,出現問題也才可以及時的發現和解決,下車!!!
本作品採用《CC 協議》,轉載必須註明作者和本文連結