Laravel / Vue刷新JWT令牌 - 令牌已被列入黑名单异常

时间:2017-10-30 11:05:49

标签: laravel-5 vuejs2 jwt axios

我在laravel中使用tymon jwt auth package进行令牌身份验证,我试图刷新JWT令牌,如果它已过期,我已经设置了一个中间件AuthenticateToken,看起来像这样:

class AuthenticateToken
{
    public function handle($request, Closure $next)
    {
        try
        {
            if (! $user = JWTAuth::parseToken()->authenticate() )
            {
                return response()->json([
                    'code'   => 401,
                    'response' => null
                ]);
            }
        }
        catch (TokenExpiredException $e)
        {
            // If the token is expired, then it will be refreshed and added to the headers
            try
            {
                $refreshed = JWTAuth::refresh(JWTAuth::getToken());
                $user = JWTAuth::setToken($refreshed)->toUser();
                header('Authorization: Bearer ' . $refreshed);
            }
            catch (JWTException $e)
            {
                return response()->json([
                    'code'   => 403,
                    'response' => null
                ]);
            }
        }
        catch (JWTException $e)
        {
            return response()->json([
                'code'   => 401,
                'response' => null
            ]);
        }

        // Login the user instance for global usage
        Auth::login($user, false);

        return  $next($request);
    }
}

我在我的路线上使用那个中间件:

    Route::group(['prefix' => 'intranet', 'middleware' => ['token']], function () {
        Route::get('intranet-post', 'Api\IntranetController@index');
    });

在Vue中,我设置了axios并刷新令牌,如下所示:

// Apply refresh(ing) token
BACKEND.defaults.transformResponse.push((data, headers) => {
  if (headers.authorization && store('token', headers.authorization)) {
    BACKEND.defaults.headers.common.authorization = headers.authorization;
  }
  return data;
});

BACKEND.defaults.transformRequest.push((data, headers) => {
  headers.authorization = `Bearer ${load('token')}`;
});

Vue.prototype.$http = axios;
Vue.prototype.$backend = BACKEND;

function store(key, value) {
  try {
    let oldLength = localStorage.length;
    localStorage.setItem(key, value);
    return !(localStorage.length > oldLength); // Returns true on write error
  }
  catch (err) {
    return true;
  }
}

function load(key) {
  try {
    return localStorage.getItem(key);
  }
  catch (err) {
    return null;
  }
}

但是,在令牌到期时,我仍然会得到403响应。如果我在这里使用中间件dd($e)

    catch (TokenExpiredException $e)
    {
        // If the token is expired, then it will be refreshed and added to the headers
        try
        {
            $refreshed = JWTAuth::refresh(JWTAuth::getToken());
            $user = JWTAuth::setToken($refreshed)->toUser();
            header('Authorization: Bearer ' . $refreshed);
        }
        catch (JWTException $e)
        {   
            dd($e);
            return response()->json([
                'code'   => 103,
                'response' => null
            ]);
        }
    }

我明白了:

  

令牌已被列入黑名单

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

试试我的中间件:

<?php

namespace App\Http\Middleware;

use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Tymon\JWTAuth\Exceptions\JWTException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;

class RefreshToken extends BaseMiddleware {

    public function handle($request, \Closure $next) {

        $this->checkForToken($request); // Check presence of a token.

        try {
            if (!$this->auth->parseToken()->authenticate()) { // Check user not found. Check token has expired.
                throw new UnauthorizedHttpException('jwt-auth', 'User not found');
            }
            $payload = $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray();
            return $next($request); // Token is valid. User logged. Response without any token.
        } catch (TokenExpiredException $t) { // Token expired. User not logged.
            $payload = $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray();
            $key = 'block_refresh_token_for_user_' . $payload['sub'];
            $cachedBefore = (int) Cache::has($key);
            if ($cachedBefore) { // If a token alredy was refreshed and sent to the client in the last JWT_BLACKLIST_GRACE_PERIOD seconds.
                \Auth::onceUsingId($payload['sub']); // Log the user using id.
                return $next($request); // Token expired. Response without any token because in grace period.
            }
            try {
                $newtoken = $this->auth->refresh(); // Get new token.
                $gracePeriod = $this->auth->manager()->getBlacklist()->getGracePeriod();
                $expiresAt = Carbon::now()->addSeconds($gracePeriod);
                Cache::put($key, $newtoken, $expiresAt);
            } catch (JWTException $e) {
                throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode());
            }
        }

        $response = $next($request); // Token refreshed and continue.

        return $this->setAuthenticationHeader($response, $newtoken); // Response with new token on header Authorization.
    }

}

有关详细信息,请参阅this post

答案 1 :(得分:0)

你可以编辑你的 config/jwt.php 关于第 224 行。

<?php
.......

'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', false),