2015-04-17 13 views
7

EDIT:Laravel JWT Token sind ungültig, nachdem sie in einer Authentifizierung JWT Ansatz aktualisieren

Lesen Sie die Diskussion über die Fehler bei: https://github.com/tymondesigns/jwt-auth/issues/83

meine ursprüngliche Frage:

Ich bin Implementieren Sie mit jwt-auth meine geschützten Ressourcen, die einen authentifizierten Benutzer mit folgendem Code benötigen:

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

Wenn sich der Benutzer bei der API anmeldet, wird ein Autorisierungstoken erstellt und an den Antwortautorisierungsheader an die Clientanwendung gesendet, die die Ressource aufruft. Also, Client-Anwendungen, wenn ein Autorisierungstoken auf Header einer Antwort abgefangen wird, setzen Sie eine Variable/Sitzung/was auch immer mit diesem Token-Wert, um bei der nächsten Anfrage erneut an API zu senden.

Die erste Anforderung für eine geschützte Ressource nach ‚login‘ funktioniert gut, aber die nächste Client-Anwendung Anforderung API mit einem aufgefrischt Token, gibt die folgende Fehlermeldung (API alle Antworten im JSON-Format Montag):

{ 
    "error": "token_invalid" 
} 

Was kann mit aufgefrischten Token passieren? Meine Refresh-Token-Implementierung (als After-Middleware festgelegt) ist falsch? Oder ist es nicht erforderlich, alle Autorisierungs-Token manuell zu aktualisieren, die mit Client-Apps-Anforderungen geliefert werden?

UPDATE:

ich die jwt-Auth RefreshToken Middleware aktualisieren, wie here schlagen, aber die token_invalid bestehen bleiben.

BUG:

Ich denke, dass ich gefunden, was passiert. Beachten Sie, dass in der Refresh-Verfahren wird das alte Token hinzugefügt Cache Fall schwarze Liste aktiviert:

// 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'] 
     ]) 
    ); 
} 

Und das beachten Sie in Add-Methode auf die schwarze Liste der Schlüssel der JTI param aus alten Token Nutzlast:

// 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; 
} 

Wenn also auf schwarze Liste Methode genannt wird, ist das alte Token JTI param die gleiche, dass die neuen, so dass die neuen Token in schwarzer Liste ist:

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

Wenn Sie die schwarze Liste Funktionalität nicht brauchen Setzen Sie in der Konfigurationsdatei jwt.php einfach den Wert false. Aber ich kann nicht sagen, ob es einer Sicherheitslücke ausgesetzt ist.

Lesen Sie die Diskussion über die Fehler bei: https://github.com/tymondesigns/jwt-auth/issues/83

+0

Hat Ihr Problem in der neuen Version 0.5.3 gelöst? Wie vom Autor erwähnt, wurde es in der neuesten Version gelöst. Aber ich habe immer noch das gleiche Problem wie Ihres. – davidcoder

+0

@davidcoder, als ich dieses Problem fand, schreibe ich einen Wrapper zu jwt-auth, um es zu lösen, weil ich eine schnelle Lösung brauchte. Grundsätzlich überschreibe ich die RefreshToken-Middleware in meinem App \ Http \ Middleware-Paket. Aber ich werde die neue Version testen, um zu überprüfen, was passiert. – Maykonn

+0

Ich kann sagen, das Problem ist immer noch an. Vielen Dank für diese Einsicht. Deaktivierung der Blacklisting funktioniert –

Antwort

3

Wenn ich dieses Problem zu erhalten, die Lösung, die ich mein Projekt gefunden zum Laufen bringen ein neues Token mit Daten aus älteren Token auf jede neue Anforderung zu erzeugen war.

Meine Lösung, die für mich funktioniert, ist schlecht, hässlich und kann mehr Probleme erzeugen, wenn Sie viele asynchrone Anfragen haben und Ihr API (oder Business Core) -Server langsam ist.

Für jetzt funktioniert, aber ich werde mehr dieses Problem untersuchen, denn nach 0.5.3 Version wird das Problem fortgesetzt.

ZB:

Anfrage 1 (GET/login):

Some guest data on token 

Anfrage 2 (POST/login Antwort):

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

Verfahrenscodebeispiel (Sie können besser = tun)), können Sie dies auf routes.php außerhalb der Routen ausführen, sage ich, das ist hässlich haha:

// ---------------------------------------------------------------- 
// 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. 
} 

Einige Route (einfaches Beispiel Benutzer Mobilgerät speichern):

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; 
    }); 
});