Laravel 配合 jwt 使用

13sai發表於2020-01-20

測試使用的是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文件

本作品採用《CC 協議》,轉載必須註明作者和本文連結

分享開發知識,歡迎交流。qq957042781

相關文章