2015-04-26 14 views
9

L'API REST funziona senza metodi di autenticazione. Ora volevo autenticare l'API REST con l'autenticazione OAuth2 per le richieste API tramite l'applicazione mobile. Ho provato con la guida di yii2, ma non ha funzionato per me.Yii 2 API RESTful autenticare con OAuth2 (modello avanzato Yii 2)

in pratica l'utente mobile deve effettuare il login con nome utente & password, se un nome utente e una password sono corretti, l'utente deve essere il login e la richiesta dell'altra API deve essere convalidata con il token.

Devo creare un client OAuth 2 personalizzato come questo? Creating your own auth clients

campo access_token nella tabella utente è vuoto. devo salvarlo manualmente? come restituire access_token come risposta?

c'è qualche motivo per l'utente tutti e tre i metodi (HttpBasicAuth, HttpBearerAuth, QueryParamAuth) in una sola volta, perché? Come?

la struttura della cartella dell'applicazione è simile a quella riportata di seguito.

api 
-config 
-modules 
--v1 
---controllers 
---models 
-runtime 
-tests 
-web 

backend 
common 
console 
environments 
frontend 

api \ moduli \ v1 \ Module.php

namespace api\modules\v1; 
class Module extends \yii\base\Module 
{ 
    public $controllerNamespace = 'api\modules\v1\controllers'; 

    public function init() 
    { 
     parent::init(); 
     \Yii::$app->user->enableSession = false;  
    } 
} 

api \ moduli \ v1 \ \ controllori CountryController.php

namespace api\modules\v1\controllers; 
use Yii; 
use yii\rest\ActiveController; 
use common\models\LoginForm; 
use common\models\User; 
use yii\filters\auth\CompositeAuth; 
use yii\filters\auth\HttpBasicAuth; 
use yii\filters\auth\HttpBearerAuth; 
use yii\filters\auth\QueryParamAuth; 

/** 
* Country Controller API 
* 
* @author Budi Irawan <[email protected]> 
*/ 
class CountryController extends ActiveController 
{ 
    public $modelClass = 'api\modules\v1\models\Country';  

    public function behaviors() 
    { 
     $behaviors = parent::behaviors(); 
     $behaviors['authenticator'] = [ 
      //'class' => HttpBasicAuth::className(), 
      'class' => CompositeAuth::className(), 
      'authMethods' => [ 
       HttpBasicAuth::className(), 
       HttpBearerAuth::className(), 
       QueryParamAuth::className(), 
      ], 
     ]; 
     return $behaviors; 
    } 

} 

modelli \ Common \ User.php

namespace common\models; 

use Yii; 
use yii\base\NotSupportedException; 
use yii\behaviors\TimestampBehavior; 
use yii\db\ActiveRecord; 
use yii\web\IdentityInterface; 

class User extends ActiveRecord implements IdentityInterface 
{ 
    const STATUS_DELETED = 0; 
    const STATUS_ACTIVE = 10; 

    public static function tableName() 
    { 
     return '{{%user}}'; 
    } 

    public function behaviors() 
    { 
     return [ 
      TimestampBehavior::className(), 
     ]; 
    } 

    public function rules() 
    { 
     return [ 
      ['status', 'default', 'value' => self::STATUS_ACTIVE], 
      ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], 
     ]; 
    } 

    public static function findIdentity($id) 
    { 
     return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); 
    } 

    public static function findIdentityByAccessToken($token, $type = null) 
    { 

     return static::findOne(['access_token' => $token]); 
    } 


} 

tabella utente

id 
username 
auth_key 
password_hash 
password_reset_token 
email 
status 
created_at 
access_token 

access_token è stato aggiunto dopo la tabella utente migrate

+0

hai trovato una soluzione? – bdart

+0

access_token deve essere generatet manualmente (ad esempio, sha1 (uniqid())). Fondamentalmente, dopo che il login (username e password) ha ricevuto il token di accesso, e lo usa in uno dei tre metodi (HttpBasicAuth, HttpBearerAuth, QueryParamAuth) in ogni altra richiesta al server. – Tahiaji

risposta

1

è possibile creare il sistema Auth, di solito lo faccio. Puoi salvare i token per ogni utente e dopo averlo autenticato da quel token. In ogni azione È possibile inviare quel token per l'utente authentify.

1

È necessario effettuare le seguenti operazioni:

  • impostare il token prima di salvare l'utente nel modello User.
  • aggiungi actionLogin in UserController per restituire auth_key all'accesso utente.
  • in ogni richiesta API si invia il auth_key nell'intestazione anziché inviando nome utente e password.
  • per verificare se il parametro auth_key è valido, definire "authenticator" nei comportamenti di 01Controller UserController.

si possono trovare esempi di codice nella mia risposta a un'altra domanda here

1

sto usando JWT per la convalida della domanda. Fondamentalmente JWT è un token che contiene anche informazioni su un utente e sul token stesso come la validità e il tempo di scadenza del token. Puoi leggere ulteriori informazioni su JWT here.

Il flusso della mia applicazione è come questo:

  • In primo luogo, quando un utente registrato, creare un JWT per l'utente

    $key = base64_decode('some_random_string'); 
    
    $tokenId = base64_encode(mcrypt_create_iv(32)); 
    $issuedAt = time(); 
    $notBefore = $issuedAt + 5; 
    $expire = $notBefore + 1800; 
    
    $user = User::findByEmail($email); 
    
    $data = [ 
        'iss' => 'your-site.com', 
        'iat' => $issuedAt, 
        'jti' => $tokenId, 
        'nbf' => $notBefore, 
        'exp' => $expire, 
        'data' => [ 
         'id' => $user->id, 
         'username' => $user->username, 
         //put everything you want (that not sensitive) in here 
        ] 
    ]; 
    
    $jwt = JWT::encode($data, $key,'HS256'); 
    
    return $jwt; 
    
  • Quindi, il client (ad esempio, il cellulare app) deve fornire il token in ogni richiesta tramite l'intestazione Authorization. L'intestazione sarà simile a questa:

    Authorization:Bearer [the JWT token without bracket]

  • Nel modello utente, aggiungere un metodo come questo per la convalida del token:

    public static function findIdentityByAccessToken($token, $type = null) { 
        $key = base64_decode('the same key that used in login function'); 
    
        try{ 
         $decoded = JWT::decode($token, $key, array('HS256')); 
         return static::findByEmail($decoded->data->email); 
        }catch (\Exception $e){ 
         return null; 
        } 
    } 
    

    La biblioteca JWT solleva un'eccezione se il token è non più valido (sono stati manomessi o hanno superato il tempo di scadenza).

  • Quindi, aggiungere questo alla funzione di comportamenti in ogni controller:

    $behaviors['authenticator'] = [ 
        'class' => HttpBearerAuth::className(), 
        'except' => ['login'] //action that you don't want to authenticate such as login 
    ]; 
    

Questo è tutto! Spero che questo lavoro come volevi. Oh, e ci sono molte librerie JWT che puoi usare (puoi vederlo here), ma io personalmente uso this library by people from firebase