在此文章中,我们将学习如何使用 JWT 身份验证在 Laravel 中构建 restful API 。 JWT 代表 JSON Web Tokens 。 我们还将使用 API 为用户产品创建功能齐全的 CRUD 应用。 在使用跨平台应用程序时, API 是一个非常不错的选择。 除了网站,您的产品可能还有 Android 和 iOS 应用程序。 在这种情况下, API 也是同样出色的,因为您可以在不更改任何后端代码的情况下编写不同的前端。 使用 API 时,只需使用一些参数点击 GET , POST 或其他类型的请求,服务器就会返回 JSON (JavaScript Object Notation) 格式的一些数据,这些数据由客户端应用程序处理。
创建新项目
#使用composer安装
composer create-project --prefer-dist laravel/laravel jwt
#使用Latavel安装器
Laravel new jwt
如果出现找不到包可切换镜像源
-
全局配置阿里镜像源
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ -
取消配置:
composer config -g --unset repos.packagist
配置JWT-AUTH扩展
如果您正在使用 Laravel 5.5 或以上版本,请运行以下命令来获取 dev-develop 版本的 JWT 包(亲测)
composer require tymon/jwt-auth
如果您正在使用 Laravel 5.4 或以下版本,那么要运行下面这条命令(未亲测)
composer require tymon/jwt-auth:dev-develop --prefer-source
对于 Laravel 版本 低于 5.5 的应用,您还要在 config/app.php 文件中设置服务提供者和别名。
'providers' => [
....
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
....
],
'aliases' => [
....
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
....
],
如果您的 Laravel 版本为 5.5 或以上,Laravel 会进行「包自动发现」。
发布配置文件
对于 5.5 或以上版本 的 Laravel,请使用下面这条命令来发布配置文件(使用Laravel8亲测)
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
对于之前 之前版本的 Laravel,那么应该运行下面这条命令(未亲测)
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
生成JWT密钥
对于 5.5 或以上版本 的 Laravel,请使用下面这条命令来发布配置文件(使用Laravel8亲测)
php artisan jwt:secret
对于之前 之前版本的 Laravel,那么应该运行下面这条命令(未亲测)
php artisan jwt:generate
注册中间件
protected $routeMiddleware = [
....
'auth.jwt' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];
这个中间件会通过检查请求中附带的令牌来校验用户的认证。如果用户未认证,这个中间件会抛出 UnauthorizedHttpException 异常。
设置API路由
找到routes/api.php 添加对应路由
Route::post('login', 'ApiController@login');
Route::post('register', 'ApiController@register');
Route::group(['middleware' => 'auth.jwt'], function () {
Route::get('logout', 'ApiController@logout');
Route::get('user', 'ApiController@getAuthUser');
Route::get('products', 'ProductController@index');
Route::get('products/{id}', 'ProductController@show');
Route::post('products', 'ProductController@store');
Route::put('products/{id}', 'ProductController@update');
Route::delete('products/{id}', 'ProductController@destroy');
});
路由服务
一、一开始的项目并默认带有命名空间前缀,需要自己加上(我创建的新项目并无添加直接设置api路由会出现控制器不存在的错误)路径app/Providers/RouteServiceProvider.php
方法1:直接添加命名空间属性
protected $namespace = 'App\Http\Controllers';
方法2:添加命名空间属性后增加三个路由映射方法--可注释掉原本boot中的方法
protected $namespace = 'App\Http\Controllers'; /**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* @var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
// parent::boot();
// $this->routes(function () {
// Route::prefix('api')
// ->middleware('api')
// ->namespace($this->namespace)
// ->group(base_path('routes/api.php'));
// Route::middleware('web')
// ->namespace($this->namespace)
// ->group(base_path('routes/web.php'));
// });
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
二、设置config/auth.php文件,设置api使用jwt验证
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false
],
],
JWT 身份验证逻辑
让我们使用 JWT 身份验证在 laravel 中写 Restful API 的逻辑。 用户注册时需要姓名,邮箱和密码。
创建一个API控制器
php artisan make:controller ApiController
修改控制器
<?php
namespace App\Http\Controllers;
use App\Http\Requests\RegisterAuthRequest;
use App\User;
use Illuminate\Http\Request;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class ApiController extends Controller
{
public $loginAfterSignUp = true;
public function register(Request $request) {
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->loginAfterSignUp) {
return $this->login($request);
}
return response()->json([
'success' => true,
'data' => $user
], 200);
}
public function login(Request $request)
{
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'success' => false,
'message' => 'Invalid Email or Password',
], 401);
}
return response()->json([
'success' => true,
'token' => $jwt_token,
]);
}
public function logout(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'success' => true,
'message' => 'User logged out successfully'
]);
} catch (JWTException $exception) {
return response()->json([
'success' => false,
'message' => 'Sorry, the user cannot be logged out'
], 500);
}
}
public function getAuthUser(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}
}
如果生成令牌的过程中出现该错误
Tymon\JWTAuth\Exceptions\JWTException: Could not create token: Using integers for registered date claims is deprecated, please use DateTimeImmutable objects instead
百度后解决方案是
'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class 改成 'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class
到此已经成功配置JWT-AUTH 验证,已经可以使用接口令牌了