将包添加到composer.json
"require": {
...
"tymon/jwt-auth": "1.0.0-rc.3"
}
然后按命令更新composer
composer update
设置配置
生成密钥
php artisan jwt:secret
发布配置文件
php artisan vendor:publish --provider="TymonJWTAuthProvidersLaravelServiceProvider"
打开app.php并添加以下行
在’aliases array’数组中
'JWTAuth'=> TymonJWTAuthFacadesJWTAuth::class,
'JWTFactory'=> TymonJWTAuthFacadesJWTFactory::class,
更新用户模型
打开User.php并为模型实现JWTSubject
use TymonJWTAuthContractsJWTSubject;
class User extends Authenticatable implements JWTSubject
并在模型中添加2个方法(在未完成的官方指南中阅读有关这些功能的更多信息)
public function getJWTIdentifier(){
return $ this-> getKey();
}
public function getJWTCustomClaims(){
return [];
}
更新配置auth.php
打开config/auth.php并将API的保护驱动程序更改为’jwt’(默认为令牌)
'guards'=> [
...
'api'=> [
'driver'=>'jwt',
'provider'=>'users',
],
],
创建登录控制器
创建controller用于login、logout、refresh等
<?php
namespace AppHttpControllersAuth;
use IlluminateSupportFacadesAuth;
use AppHttpControllersController;
class JwtAuthController extends Controller
{
/**
* Create a new AuthController instance.
*
*
* @return void
*/
public function __construct()
{
$this->middleware('jwt.auth', ['except' => ['login']]);
// 另外关于上面的中间件,官方文档写的是『auth:api』
// 但是我推荐用 『jwt.auth』,效果是一样的,但是有更加丰富的报错信息返回
}
/**
* Get a JWT via given credentials.
*
* @return IlluminateHttpJsonResponse
*/
public function login()
{
$credentials = request(['email', 'password']);
if (! $token = auth('api')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Get the authenticated User.
*
* @return IlluminateHttpJsonResponse
*/
public function me()
{
return response()->json(auth('api')->user());
}
/**
* Log the user out (Invalidate the token).
*
* @return IlluminateHttpJsonResponse
*/
public function logout()
{
auth('api')->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
* 刷新token,如果开启黑名单,以前的token便会失效。
* 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的Token是并行的,即两个都可用。
* @return IlluminateHttpJsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth('api')->refresh());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return IlluminateHttpJsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
]);
}
}
创建路由
打开routes/api.php
然后添加一些路由
Route::group(['prefix' => 'auth'], function () {
Route::post('login', 'Auth\JwtAuthController@login');
Route::post('logout', 'Auth\JwtAuthController@logout');
Route::post('refresh', 'Auth\JwtAuthController@refresh');
Route::post('me', 'Auth\JwtAuthController@me');
});
然后在标头请求中添加“Authorization:Bearer {token}”
如果你想捕获异常 在你的app/Exceptions/Handler.php中捕获’render’函数中的错误。
use SymfonyComponentHttpKernelExceptionUnauthorizedHttpException;
……
if ($exception instanceof UnauthorizedHttpException) {
$preException = $exception->getPrevious();
if ($preException instanceof
TymonJWTAuthExceptionsTokenExpiredException) {
return response()->json(['error' => 'TOKEN_EXPIRED']);
} else if ($preException instanceof
TymonJWTAuthExceptionsTokenInvalidException) {
return response()->json(['error' => 'TOKEN_INVALID']);
} else if ($preException instanceof
TymonJWTAuthExceptionsTokenBlacklistedException) {
return response()->json(['error' => 'TOKEN_BLACKLISTED']);
}
if ($exception->getMessage() === 'Token not provided') {
return response()->json(['error' => 'Token not provided']);
}
}
验证用户登录
php artisan make:middleware RefreshToken
中间件代码如下:
RefreshToken.php
<?php
namespace AppHttpMiddleware;
use Auth;
use Closure;
use TymonJWTAuthExceptionsJWTException;
use TymonJWTAuthHttpMiddlewareBaseMiddleware;
use TymonJWTAuthExceptionsTokenExpiredException;
use SymfonyComponentHttpKernelExceptionUnauthorizedHttpException;
// 注意,我们要继承的是 jwt 的 BaseMiddleware
class RefreshToken extends BaseMiddleware
{
/**
* Handle an incoming request.
*
* @param IlluminateHttpRequest $request
* @param Closure $next
*
* @throws SymfonyComponentHttpKernelExceptionUnauthorizedHttpException
*
* @return mixed
*/
public function handle($request, Closure $next)
{
// 检查此次请求中是否带有 token,如果没有则抛出异常。
$this->checkForToken($request);
// 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常
try {
// 检测用户的登录状态,如果正常则通过
if ($this->auth->parseToken()->authenticate()) {
return $next($request);
}
throw new UnauthorizedHttpException('jwt-auth', '未登录');
} catch (TokenExpiredException $exception) {
// 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
try {
// 刷新用户的 token
$token = $this->auth->refresh();
// 使用一次性登录以保证此次请求的成功
Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);
} catch (JWTException $exception) {
// 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
}
}
// 在响应头中返回新的 token
return $this->setAuthenticationHeader($next($request), $token);
}
}