Laravel JWT令牌是无效的刷新他们的认证JWT方法后

问题描述:

编辑:Laravel JWT令牌是无效的刷新他们的认证JWT方法后

阅读有关的错误的讨论:https://github.com/tymondesigns/jwt-auth/issues/83

我原来的问题:

我与jwt-auth实现需要与娄代码验证的用户我的受保护的资源:

Route::group(['middleware' => ['before' => 'jwt.auth', 'after' => 'jwt.refresh']], function() { 
    // Protected routes 
}); 

当用户“登录”上的API的授权令牌被创建,并且在响应授权报头发送到调用资源客户端应用程序。这样,客户端应用程序时截距上的任何响应的报头中的授权令牌,设置一个变量/会话/不管与该令牌值,再次发送到API上下一请求。

为“登陆”后的受保护资源的第一个请求工作正常,但接下来的客户端应用程序请求与刷新令牌API,提供了以下错误(API安装JSON格式的所有响应):

{ 
    "error": "token_invalid" 
} 

什么都可以用刷新令牌发生的呢?我的刷新标记实现(设置为中间件后)是错误的?或者没有必要手动刷新客户端应用程序请求附带的所有授权令牌?

UPDATE:

我更新JWT-auth的RefreshToken中间件提出here,但token_invalid坚持。

BUG:

我猜,我发现发生了什么。请注意,在刷新方法,老令牌被添加到黑名单启用缓存情况:

// Tymon\JWTAuth\JWTManager 
public function refresh(Token $token) 
{ 
    $payload = $this->decode($token); 

    if ($this->blacklistEnabled) { 
     // invalidate old token 
     $this->blacklist->add($payload); 
    } 

    // return the new token 
    return $this->encode(
     $this->payloadFactory->setRefreshFlow()->make([ 
      'sub' => $payload['sub'], 
      'iat' => $payload['iat'] 
     ]) 
    ); 
} 

,并注意添加到黑名单方法的关键是从旧令牌有效载荷的JTI PARAM:

// Tymon\JWTAuth\Blacklist 
public function add(Payload $payload) 
{ 
    $exp = Utils::timestamp($payload['exp']); 

    // there is no need to add the token to the blacklist 
    // if the token has already expired 
    if ($exp->isPast()) { 
     return false; 
    } 

    // add a minute to abate potential overlap 
    $minutes = $exp->diffInMinutes(Utils::now()->subMinute()); 

    $this->storage->add($payload['jti'], [], $minutes); 

    return true; 
} 

因此,对黑名单方法被调用时,旧的令牌JTI参数是相同的,新的,所以新的令牌是黑名单:

// Tymon\JWTAuth\Blacklist 
public function has(Payload $payload) 
{ 
    return $this->storage->has($payload['jti']); 
} 

如果您不需要黑名单功能在jwt.php配置文件中设置为false。但是我不能说它是否暴露在某种安全漏洞之中。

阅读有关的错误的讨论:https://github.com/tymondesigns/jwt-auth/issues/83

+0

拥有新版本0.5.3已经解决了您的问题?正如作者所提到的,它已经在最新版本中得到解决。但我仍然有像你一样的问题。 – davidcoder

+0

@davidcoder当我发现这个问题时,我写了一个包装到jwt-auth来解决它,因为我需要一个快速的解决方案。基本上我在App \ Http \ Middleware包中覆盖了RefreshToken中间件。但我会测试新版本来验证发生了什么。 – Maykonn

+0

我可以告诉问题仍然存在。 非常感谢您的洞察力。禁用黑名单工作 –

当我得到这个问题,我发现让我的项目的工作是从每个新的请求旧的令牌生成数据的新令牌的解决方案。

我的解决方案,为我的作品,是坏的,丑陋的,如果你有许多异步请求和您的API(或业务的核心)可以产生更多的问题,服务器速度慢。

现在正在工作,但我会调查更多这个问题,导致0.5.3版本问题继续。

例如:

请求1(GET /登录):

Some guest data on token 

请求2(POST /登录响应):

User data merged with guest data on old token generating a new token 

程序代码示例(可以做得更好= )),你可以在routes.php中运行这个路由,我说这很丑陋哈哈:

// ---------------------------------------------------------------- 
// AUTH TOKEN WORK 
// ---------------------------------------------------------------- 
$authToken = null; 
$getAuthToken = function() use ($authToken, $Response) { 
    if($authToken === null) { 
     $authToken = JWTAuth::parseToken(); 
    } 
    return $authToken; 
}; 

$getLoggedUser = function() use ($getAuthToken) { 
    return $getAuthToken()->authenticate(); 
}; 

$getAuthPayload = function() use ($getAuthToken) { 
    try { 
     return $getAuthToken()->getPayload(); 
    } catch (Exception $e) { 
     return []; 
    } 
}; 

$mountAuthPayload = function($customPayload) use ($getLoggedUser, $getAuthPayload) { 
    $currentPayload = []; 
    try { 
     $currentAuthPayload = $getAuthPayload(); 
     if(count($currentAuthPayload)) { 
      $currentPayload = $currentAuthPayload->toArray(); 
     } 
     try { 
      if($user = $getLoggedUser()) { 
       $currentPayload['user'] = $user; 
      } 
      $currentPayload['isGuest'] = false; 
     } catch (Exception $e) { 
      // is guest 
     } 
    } catch(Exception $e) { 
     // Impossible to parse token 
    } 

    foreach ($customPayload as $key => $value) { 
     $currentPayload[$key] = $value; 
    } 

    return $currentPayload; 
}; 

// ---------------------------------------------------------------- 
// AUTH TOKEN PAYLOAD 
// ---------------------------------------------------------------- 
try { 
    $getLoggedUser(); 
    $payload = ['isGuest' => false]; 
} catch (Exception $e) { 
    $payload = ['isGuest' => true]; 
} 

try { 
    $payload = $mountAuthPayload($payload); 
} catch (Exception $e) { 
    // Make nothing cause token is invalid, expired, etc., or not exists. 
    // Like a guest session. Create a token without user data. 
} 

一些航线(简单的例子,以节省用户的移动设备):

Route::group(['middleware' => ['before' => 'jwt.auth', 'after' => 'jwt.refresh']], function() use ($getLoggedUser, $mountAuthPayload) { 
    Route::post('/session/device', function() use ($Response, $getLoggedUser, $mountAuthPayload) { 
     $Response = new \Illuminate\Http\Response(); 
     $user = $getLoggedUser(); 

     // code to save on database the user device from current "session"... 

     $payload = app('tymon.jwt.payload.factory')->make($mountAuthPayload(['device' => $user->device->last()->toArray()])); 
     $token = JWTAuth::encode($payload); 
     $Response->header('Authorization', 'Bearer ' . $token); 

     $responseContent = ['setted' => 'true']; 

     $Response->setContent($responseContent); 
     return $Response; 
    }); 
});