Hướng dẫn cài đặt và sử dụng laravel jwt token giúp xác thực quyền truy cập khi sử dụng REST api.
JSON Web Token (JWT) là một tiêu chuẩn mở (RFC 7519) giúp bảo mật khi truyền thông tin giữa các bên dưới dạng đối tượng json.
Thông tin người dùng(username và password) sẽ được gửi lên server sử dụng HTTP POST request, server sẽ xác thực thông tin người dùng và tạo 1 JWT token trả về cho client, client sẽ lưu lại nó ở local storage và mỗi lần request đến server token sẽ được gửi lên sever để xác thực, nếu token hợp lệ client sẽ nhận được responsive từ server.
1. Cài đặt tymondesigns/jwt-auth
package thông qua composer
composer require tymon/jwt-auth
2. Đăng kí service provider: nếu laravel version thấp hơn 5.4 cần đăng kí thủ công, còn các version lớn hơn sẽ được đăng kí tự động, thêm provider trong file config/app.php
'providers' => [
...
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
3. Public config, chạy command bên dưới để public config
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
4. Generate secret key Tạo secret key với command
php artisan jwt:secret
Sau khi chạy command key sẽ được sinh ra trong file .env
, key này được dùng để generate và verify token. Nếu bạn dùng nhiều server cần đảm bảo các server sử dụng chung 1 secret key.
JWT_SECRET=foobar
1. Update user model Model User cần implement Tymon\JWTAuth\Contracts\JWTSubject
và require 2 method getJWTIdentifier()
và getJWTCustomClaims()
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* 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 [];
}
}
2. Config auth guard
Config guard api
sử dụng JWT token driver
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false,
],
],
3. Create auth controller
Create AuthController sử dụng để viết các chức đăng nhập, đăng kí ... Tạo controller sử dụng command
php artisan make:controller AuthController
file controller được tạo tự động trong thư mục app/Http/Controllers/AuthController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Validator;
class AuthController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct() {
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login(Request $request){
$validator = Validator::make($request->all(), [
'email' => 'required|email',
'password' => 'required|string|min:6',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$credentials = $request->only(['email', 'password']);
if (! $token = auth()->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->createNewToken($token);
}
/**
* Register a User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function register(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required|string|between:2,100',
'email' => 'required|string|email|max:100|unique:users',
'password' => 'required|string|confirmed|min:6',
]);
if($validator->fails()){
return response()->json($validator->errors()->toJson(), 400);
}
$user = User::create(array_merge(
$validator->validated(),
['password' => bcrypt($request->password)]
));
return response()->json([
'message' => 'User successfully registered',
'user' => $user
], 201);
}
/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout() {
auth()->logout();
return response()->json(['message' => 'User successfully signed out']);
}
/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh() {
return $this->createNewToken(auth()->refresh());
}
/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function userProfile() {
return response()->json(auth()->user());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function createNewToken($token){
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
4. Add midleware to route
Thêm route trong file routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group([
'middleware' => 'api',
'prefix' => 'auth'
], function ($router) {
Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::post('/refresh', [AuthController::class, 'refresh']);
Route::get('/user-profile', [AuthController::class, 'userProfile']);
});
Ngoài cách trên cũng có thể viết một middleware để check auth với JWT token như sau Create middlleware App\Http\Middleware\ApiAuthMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Illuminate\Http\Response;
class ApiAuthMiddleware extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
try {
$this->auth->parseToken()->authenticate();
if (Auth::guard('api')->check()) {
return $next($request);
}
return response()->json(['error' => __('messages.errors.auth.token.unauthorized')], Response::HTTP_UNAUTHORIZED);
} catch (JWTException $e) {
if ($e instanceof TokenInvalidException) {
return response()->json(['error' => __('messages.errors.auth.token.invalid')], Response::HTTP_UNAUTHORIZED);
}
if ($e instanceof TokenExpiredException) {
return response()->json(['error' => __('messages.errors.auth.token.expired')], Response::HTTP_UNAUTHORIZED);
}
return response()->json(['error' => __('messages.errors.auth.token.internal_error')], Response::HTTP_UNAUTHORIZED);
}
}
}
Đăng kí middleware trong App\Http\Kernel.php
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'api.auth' => \Modules\Api\Http\Middleware\ApiAuthMiddleware::class,
];
Đăng kí route theo cách 2
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::group([
'middleware' => 'api.auth',
'prefix' => 'auth'
], function ($router) {
Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::post('/refresh', [AuthController::class, 'refresh']);
Route::get('/user-profile', [AuthController::class, 'userProfile']);
});
Nhưng vậy là chúng ta đã thiết lập xong các api, giờ công việc của bạn là dùng postman để test lại các api.