2015-04-17 15 views
7

EDIT:laravel JWT gettoni non sono valide dopo di loro aggiornamento in un'autenticazione approccio JWT

Leggi la discussione sul bug in: https://github.com/tymondesigns/jwt-auth/issues/83

mia domanda iniziale:

Sono implementare con jwt-auth le mie risorse protette che richiedono un utente autenticato con codice qui sotto:

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

Quando l'utente "accede" all'API viene creato un token di autorizzazione e inviato sull'intestazione Autorizzazione di risposta all'applicazione client che chiama la risorsa. Quindi, le applicazioni client quando intercettano un token di autorizzazione sull'intestazione di qualsiasi risposta, impostano una variabile/sessione/qualsiasi cosa con questo valore di token, per inviare di nuovo all'API alla successiva richiesta.

La prima richiesta per una risorsa protetta dopo il 'login' funziona bene, ma la richiesta successiva applicazione client API con un token rinfrescato, dà il seguente errore (API montare tutte le risposte in formato JSON):

{ 
    "error": "token_invalid" 
} 

Cosa può succedere con i token aggiornati? L'implementazione del token di aggiornamento (impostato come middleware successivo) è errata? O non è necessario aggiornare manualmente tutti i token di autorizzazione forniti con le richieste delle app client?

UPDATE:

aggiorno il RefreshToken middleware JWT-auth come proporre here, ma il token_invalid persistono.

ERRORE:

Credo che ho trovato quello che succede. Si noti che nel metodo di aggiornamento, è aggiunto vecchio token per lista nera caso di cache abilitata:

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

E notate che nel Inserisci nella lista nera metodo la chiave è il param ITC dal vecchio carico utile token:

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

così, quando si è sulla lista nera metodo viene chiamato, il vecchio token ITC param è lo stesso che il nuovo, in modo che il nuovo token è in lista nera:

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

Se non è necessario la funzionalità lista nera appena impostato su false sul file di configurazione jwt.php. Ma non posso dire se esponga a qualche vulnerabilità di sicurezza.

Leggi la discussione sul bug in: https://github.com/tymondesigns/jwt-auth/issues/83

+0

È il problema stato risolto nella nuova versione 0.5.3? Come menzionato dall'autore, è stato risolto nell'ultima versione. Ma ho ancora lo stesso problema come il tuo. – davidcoder

+0

@davidcoder quando ho trovato questo problema, scrivo un wrapper su jwt-auth per risolverlo, perché avevo bisogno di una soluzione veloce. Fondamentalmente sovrascrivo il middleware RefreshToken nel mio pacchetto App \ Http \ Middleware. Ma testerò la nuova versione per verificare cosa succede. – Maykonn

+0

Posso dire che il problema è ancora attivo. Grazie mille per questa intuizione. Disabilitare la lista nera ha funzionato –

risposta

3

Quando torno a questo problema, la soluzione che ho trovato per ottenere il mio progetto di lavoro era di generare un nuovo token con i dati dal vecchio gettone su ogni nuova richiesta.

La mia soluzione, che funziona per me, è brutta, brutta e può generare più problemi se hai molte richieste asincrone e il tuo server API (o core aziendale) è lento.

Per ora funziona, ma esaminerò più questo problema, perché dopo la versione 0.5.3 il problema continua.

Esempio:

Richiesta 1 (GET/login):

Some guest data on token 

richiesta 2 (risposta POST/login):

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

esempio di codice procedurale (si può fare meglio =)), è possibile eseguire questo su routes.php di percorsi, dico che è brutto 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. 
} 

Alcuni percorso (esempio semplice per salvare dispositivo mobile dell'utente):

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