Laravel 配合 jwt 使用

测试使用的是Laravel5.5版本。

安装

composer require tymon/jwt-auth=1.0.0-rc.5

配置

生成配置

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

php artisan jwt:secret

auth配置

<?php

return [
    ...

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        // 使用jwt
        'api' => [
            'driver' => 'jwt',
            'provider' => 'apiUser',
        ],
    ],


    'providers' => [
        ...
        // 指定model
        'apiUser' => [
            'driver' => 'eloquent',
            'model' => App\ApiUser::class,
        ],    
    ],
];

编码

控制器:

<?php

namespace App\Http\Controllers\Api;

use App\ApiUser;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;

class AuthController extends Controller
{
    /**
     * 中间件去除login和refresh
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login','refresh']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $credentials = $request->only('phone', 'password');

        if (count($credentials) < 2) {
            return response()->json(['error' => 'Unauthorized'], 401);
        } 

        $user = ApiUser::where('phone', $credentials['phone'])
            ->where('password', md5($credentials['password']))
            ->first();
        if (empty($user) || !$token = JWTAuth::fromUser($user)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }
        // dd($token);

        return $this->respondWithToken($token);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth('api')->user());
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth('api')->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }
}

路由:

此处注意,我为了方便测试,使用了get方法,生产环境不建议使用get。
// routes/api.php

Route::middleware('api')->prefix('auth')->namespace('Api')->group(function () {
    Route::get('login', 'AuthController@login');
    Route::post('logout', 'AuthController@logout');
    Route::get('refresh', 'AuthController@refresh');
    Route::get('me', 'AuthController@me');
});

测试一下:

Laravel
Laravel
Laravel

unauthenticated处理

这里需要注意下,unauthenticated处理一下比较好,否则会默认跳转login登录页面。

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Auth\AuthenticationException;

class Handler extends ExceptionHandler
{
    ...

    protected function unauthenticated($request, AuthenticationException $exception)
    {
        return response()->json(['message' => 'Unauthenticated.'], 401);
         /*非api可以这么处理
        return $request->expectsJson()
                    ? response()->json(['message' => 'Unauthenticated.'], 401)
                    : redirect()->guest(route('login'));
                    */
    }
}

加入token refresh

加入中间件代码:

<?php
namespace App\Http\Middleware;
  
use Closure;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Illuminate\Auth\AuthenticationException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Illuminate\Http\Exceptions\HttpResponseException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class RefreshToken extends BaseMiddleware
{

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {  
        try{
            //检查请求中是否带有token 如果没有token值则抛出异常
            $this->checkForToken($request); 
            if ($request->user = JWTAuth::parseToken()->authenticate()) {       
                return $next($request);
            }
            throw new AuthenticationException('Unauthorized', []);
        }catch (TokenExpiredException $exception){
            //返回特殊的code
            throw new HttpResponseException(response()->json([
                'message' => 'token expired'
            ]));
        } catch (\Exception $exception) {
            throw new AuthenticationException('Unauthorized', []);
        }
    }
}

注册:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    ...
    protected $routeMiddleware = [
        'token.refresh' => \App\Http\Middleware\RefreshToken::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}

相应的控制器构造函数修改:

public function __construct()
{
        $this->middleware('token.refresh', ['except' => ['login','refresh']]);
}

把token时间设置成1分钟,测试一下。

Laravel 配合 jwt 使用

可以根据api返回,去调用刷新接口。

简单使用就是这样啦。更多使用可以看下站内其他文章:
JWT 完整使用详解
jwt-auth文档

阅读 123

推荐阅读