malvik-lab / laravel-jwt
Laravel JSON Web Token 认证
1.0.16
2024-05-12 18:27 UTC
Requires
- php: ^8.2
- firebase/php-jwt: ^6.8
- illuminate/auth: ^10.24
README
Laravel JWT 是一个开源库,为 Laravel 项目添加 JWT 认证功能。
JWT 是一种基于令牌的认证方法,它安全、轻量级且易于实现。该库易于使用,几分钟内即可配置。它提供了 JWT 认证的一系列功能,包括
- 生成和验证 JWT 令牌
- 管理用户和令牌
- 保护路由和控制器
预安装(非必需)
JWT 使用一对公钥和私钥来签名和验证令牌。公钥用于客户端验证令牌,私钥用于服务器端签名令牌。
默认情况下,该库将公钥和私钥存储在项目根目录下名为 keys 的文件夹中。您可以通过向 .env 文件中添加以下内容来更改此文件夹的位置
JWT_KEYS_DIRECTORY_PATH=/path/to/jwt/keys/directory
库安装
此命令将安装库及其所有依赖项。
composer require malvik-lab/laravel-jwt
发布配置
此文件包含库配置,例如令牌签名方法、令牌有效期限和 JWT 密钥路径。
php artisan vendor:publish --tag=jwt-config
迁移发布
此文件将在您的数据库中创建 jwt_tokens 表。此表用于存储发行的 JWT 令牌。
php artisan vendor:publish --tag=jwt-migration
运行迁移
此命令将在您的数据库中创建 jwt_tokens 表。
php artisan migrate
JWT 密钥生成
此命令将生成一对公钥和私钥,这些密钥将用于签名和验证 JWT 令牌。
php artisan jwt:keys
添加守卫
向 auth 配置文件中添加新的守卫。
<?php ## config/auth.php return [ // ... 'guards' => [ // ... 'jwt-access-token' => [ 'driver' => 'jwt-access-token', 'provider' => 'users', ], 'jwt-refresh-token' => [ 'driver' => 'jwt-refresh-token', 'provider' => 'users', ] ], // ... ];
启用 JWT API 认证
<?php ## app/Providers/AuthServiceProvider.php namespace App\Providers; // ... use Illuminate\Support\Facades\Auth; use Illuminate\Contracts\Foundation\Application; use MalvikLab\LaravelJwt\Http\Guards\JwtAccessTokenGuard; use MalvikLab\LaravelJwt\Http\Guards\JwtRefreshTokenGuard; class AuthServiceProvider extends ServiceProvider { protected $policies = [ // ... ]; public function boot(): void { // ... Auth::extend('jwt-access-token', function (Application $app, string $name, array $config) { return new JwtAccessTokenGuard(Auth::createUserProvider($config['provider'])); }); Auth::extend('jwt-refresh-token', function (Application $app, string $name, array $config) { return new JwtRefreshTokenGuard(Auth::createUserProvider($config['provider'])); }); } }
路由
为了测试 JWT 认证,您可以在项目中添加允许使用有效的 JWT 令牌进行认证的路由。
<?php ## app/routes/api.php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; use MalvikLab\LaravelJwt\Http\Controllers\AuthController; Route::middleware(['guest'])->group(function () { Route::post('/auth/login', [AuthController::class, 'login']); }); Route::middleware(['auth:jwt-access-token'])->group(function () { Route::post('/auth/logout', [AuthController::class, 'logout']); Route::get('/auth/me', [AuthController::class, 'me']); }); Route::middleware(['auth:jwt-refresh-token'])->group(function () { Route::post('/auth/refresh', [AuthController::class, 'refresh']); });
控制器
对于基本使用,您可以使用 MalvikLab\LaravelJwt\Http\Controllers\AuthController(如前例所示),或使用自定义控制器以获得对认证逻辑的更大控制。
<?php namespace App\Http\Controllers; use Illuminate\Contracts\Auth\Guard; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; use MalvikLab\LaravelJwt\Services\AuthService\AuthService; use MalvikLab\LaravelJwt\Services\JwtService\TokenOptions; class AuthController extends Controller { private AuthService $authService; private Guard $accessTokenGuard; public function __construct() { $this->authService = new AuthService(); $this->accessTokenGuard = Auth::guard('jwt-access-token'); } public function login(Request $request): JsonResponse { // Validate the request and retrieve the user // or use the Auth Service method $user = $this->authService->checkCredentials($request->all()); $options = new TokenOptions(); $options->setRole('mod'); $options->setPermissions([ 'add-post', 'edit-post', 'delete-post' ]); $options->setAccessTokenTtl(14400); $options->setRefreshTokenTtl(2592000); $this->accessTokenGuard->login($user, $options); return $this->accessTokenGuard->response(); } public function me(Request $request): JsonResponse { $authToken = $this->accessTokenGuard->getAuthToken(); $this->accessTokenGuard->hasRole('mod'); $this->accessTokenGuard->hasRoles(['mod', 'other-role']); $this->accessTokenGuard->hasPermission('add-post'); $this->accessTokenGuard->hasPermissions(['add-post', 'edit-post', 'delete-post']); return response()->json($request->user()); } }
推荐但非必需
为了确保始终返回 JSON 响应,建议执行以下操作
添加渲染方法
<?php ## app/Exceptions/Handler.php namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Response; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Throwable; class Handler extends ExceptionHandler { protected $dontFlash = [ // ... ]; public function register(): void { $this->reportable(function (Throwable $e) { // }); } public function render($request, Throwable $e): Response | JsonResponse | RedirectResponse |SymfonyResponse { if ( $request->is('api/*') ) { $request->headers->set('accept', 'application/json'); } return parent::render($request, $e); } }
添加 AcceptJson 中间件
<?php ## app/Http/Kernel.php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { protected $middleware = [ // ... ]; protected $middlewareGroups = [ 'web' => [ // ... ], 'api' => [ \MalvikLab\LaravelJwt\Http\Middleware\AcceptJson::class, // ... ], ]; // ... }
安装完成
现在您已安装 Laravel JWT 库,可以开始使用其功能。以下是您可以使用来测试 JWT 认证的一些请求和响应示例。
登录
请求
POST /api/auth/login HTTP/1.1 { "email": "john.doe@example.com", "password": "123456789" }
响应
HTTP/1.1 200 OK Content-Type: application/json { "token_type": "Bearer", "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0Iiwic3ViIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwidG9rZW5fdHlwZSI6IkFDQ0VTU19UT0tFTiIsImlhdCI6MTY5NjA2ODE2OCwianRpIjoiMzc4OWFlZmUtMWUxZC00ODI3LWFjZjEtNWY1MWJkYTAzMWY5IiwiZXhwIjoxNjk2MDgyNTY4LCJ1c2VyIjp7ImlkIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSJ9fQ.fhwqM01o6ieNoegkczJGdlB5xEcLyD6ZHWu-0avS7WZhUp5iUQLdF6_qMKpWvgiuiPYoPtxrAowG3SIbYakjYSr1pdnBrN9Pg2T4ONTqYO0VQiVCEYujvN-XHKcsG4xvkkdVxe2v75_nFPxnWxVFgg3xQZFmjuoUtpFWHf5TQSjIebDxMwO1wDseohI-8GlP69rGR-8KIWh9Ig_fPRz_Hsrjognhi8Q6vZpW4w3e0uW2xyCa4gpF-JfKHvR1qXRFyaZFD2MuP614U740Xk3Gbqc0YTzbNzYBWbivtcjZs8d6QobBE1-KJjqoDtHQ3RV9nuV0SSGvrABxpW4dFOcxWg", "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0Iiwic3ViIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwidG9rZW5fdHlwZSI6IlJFRlJFU0hfVE9LRU4iLCJpYXQiOjE2OTYwNjgxNjgsImp0aSI6IjRhNTBlOWE5LWQ2MzktNGZmNy05NWI2LTA2NzAxYjUxMjMzZCIsImV4cCI6MTY5ODY2MDE2OH0.A-keVY5H-smKTRGVlVWLosmftK4f-927tfPVKxALznumQN4L2Q3xN4bmi-6mkHp8XBZZvtKLdAXZzWCMRwz4_EvGg02lNbGnZoI7qQ-scHGu7zDc3Bbs-_FXCCYchrSijo-rtjAlAoD1c6ilr9VYXjOq6-QBAJvx10v-IjGZRcsXiveef7XFYwEz9rb605lQdvpNLOoulGT3R43BXlszbfObqWBz-WObBlL-AVPleiiHAbDNLRdisJhv-XyV1G4YKY_SLEMv7u8q09t5J6L1aj3Reya3bSm4JEJP6-3WZIUzIopaVhSVJd4SjHjr0F4iSDR73rQYtdaWYYtHRs3-YQ", "expire_in": 14400 }
我
请求
GET /api/auth/me HTTP/1.1 Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0Iiwic3ViIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwidG9rZW5fdHlwZSI6IkFDQ0VTU19UT0tFTiIsImlhdCI6MTY5NjA2ODE2OCwianRpIjoiMzc4OWFlZmUtMWUxZC00ODI3LWFjZjEtNWY1MWJkYTAzMWY5IiwiZXhwIjoxNjk2MDgyNTY4LCJ1c2VyIjp7ImlkIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSJ9fQ.fhwqM01o6ieNoegkczJGdlB5xEcLyD6ZHWu-0avS7WZhUp5iUQLdF6_qMKpWvgiuiPYoPtxrAowG3SIbYakjYSr1pdnBrN9Pg2T4ONTqYO0VQiVCEYujvN-XHKcsG4xvkkdVxe2v75_nFPxnWxVFgg3xQZFmjuoUtpFWHf5TQSjIebDxMwO1wDseohI-8GlP69rGR-8KIWh9Ig_fPRz_Hsrjognhi8Q6vZpW4w3e0uW2xyCa4gpF-JfKHvR1qXRFyaZFD2MuP614U740Xk3Gbqc0YTzbNzYBWbivtcjZs8d6QobBE1-KJjqoDtHQ3RV9nuV0SSGvrABxpW4dFOcxWg
响应
HTTP/1.1 200 OK Content-Type: application/json { "id": "9a3e2949-c70e-4faf-a301-ed72ea8c9739", "name": "John Doe", "email": "john.doe@example.com" }
刷新令牌
请求
POST /api/auth/refresh HTTP/1.1 Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0Iiwic3ViIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwidG9rZW5fdHlwZSI6IlJFRlJFU0hfVE9LRU4iLCJpYXQiOjE2OTYwNjgxNjgsImp0aSI6IjRhNTBlOWE5LWQ2MzktNGZmNy05NWI2LTA2NzAxYjUxMjMzZCIsImV4cCI6MTY5ODY2MDE2OH0.A-keVY5H-smKTRGVlVWLosmftK4f-927tfPVKxALznumQN4L2Q3xN4bmi-6mkHp8XBZZvtKLdAXZzWCMRwz4_EvGg02lNbGnZoI7qQ-scHGu7zDc3Bbs-_FXCCYchrSijo-rtjAlAoD1c6ilr9VYXjOq6-QBAJvx10v-IjGZRcsXiveef7XFYwEz9rb605lQdvpNLOoulGT3R43BXlszbfObqWBz-WObBlL-AVPleiiHAbDNLRdisJhv-XyV1G4YKY_SLEMv7u8q09t5J6L1aj3Reya3bSm4JEJP6-3WZIUzIopaVhSVJd4SjHjr0F4iSDR73rQYtdaWYYtHRs3-YQ
响应(与登录响应相同)
登出
请求
POST /api/auth/logout HTTP/1.1 Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0Iiwic3ViIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwidG9rZW5fdHlwZSI6IkFDQ0VTU19UT0tFTiIsImlhdCI6MTY5NjA2ODE2OCwianRpIjoiMzc4OWFlZmUtMWUxZC00ODI3LWFjZjEtNWY1MWJkYTAzMWY5IiwiZXhwIjoxNjk2MDgyNTY4LCJ1c2VyIjp7ImlkIjoiOWEzZTI5NDktYzcwZS00ZmFmLWEzMDEtZWQ3MmVhOGM5NzM5IiwibmFtZSI6IkpvaG4gRG9lIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSJ9fQ.fhwqM01o6ieNoegkczJGdlB5xEcLyD6ZHWu-0avS7WZhUp5iUQLdF6_qMKpWvgiuiPYoPtxrAowG3SIbYakjYSr1pdnBrN9Pg2T4ONTqYO0VQiVCEYujvN-XHKcsG4xvkkdVxe2v75_nFPxnWxVFgg3xQZFmjuoUtpFWHf5TQSjIebDxMwO1wDseohI-8GlP69rGR-8KIWh9Ig_fPRz_Hsrjognhi8Q6vZpW4w3e0uW2xyCa4gpF-JfKHvR1qXRFyaZFD2MuP614U740Xk3Gbqc0YTzbNzYBWbivtcjZs8d6QobBE1-KJjqoDtHQ3RV9nuV0SSGvrABxpW4dFOcxWg
响应
HTTP/1.1 204 No Content