2015-05-25 12 views
7

Ho problemi con la seguente azione "/ login" azione percorso nella mia classe UsersControllerYii2 Rest - metodo di azione personalizzato e OPZIONI

public function actionLogin(){ 
     $data = Yii::$app->getRequest()->getBodyParams(); 
     $model = new Usuario(); 

     //Validamos que se hayan recibido los campos 
     if(empty($data['email']) || empty($data['password'])){ 
      throw new \yii\web\BadRequestHttpException("Debe ingresar email y password"); 
     } 

     //Validamos usuario y contraseña 
     $usuario = $model->findByUsername($data['email']); 
     if(empty($usuario) || !$usuario->validatePassword($data['password'])){ 
      throw new \yii\web\UnauthorizedHttpException("Usuario y/o contraseña incorrectos"); 
     } 
     return $usuario; 
    } 

La situazione è che sto usando il metodo POST per effettuare login e sto chiamando questa rotta da un dominio diverso, quindi la libreria di frontend prova prima a chiamare/login route con il metodo OPTIONS per verificare se è permesso o non chiamare/login con POST ..

Il problema è che la funzionalità integrata di yii2 resto ActiveController è solo per/users e/users/{id}

Se aggiungo manualmente questo/percorso di accesso per essere disponibile sia in POST che in OPZIONI tramite le azioni verbFilter, quindi yii sta provando a chiamare effettivamente l'azione di login con la richiesta OPTIONS. Voglio dire, sta cercando di eseguire il login. Certo che non può, perché non sta inviando campi email e password, ma posso vedere un errore nel file di registro.

Quindi, la mia domanda è ... Esiste un modo per configurare correttamente queste azioni di percorso "personalizzate" e rendere OPZIONI eseguite in modo trasparente? Perché mi aspetto che l'azione di accesso non venga eseguita quando la si chiama con OPTIONS, ma invece di restituire direttamente le intestazioni dei metodi consentiti OPTIONS.

Aggiorna informazioni: Gestione regole Aggiunto URL

'urlManager' => [ 
     'enablePrettyUrl' => true, 
     'enableStrictParsing' => true, 
     'showScriptName' => true, 
     'rules' => [ 
      [ 
       'class' => 'yii\rest\UrlRule', 
       'controller' => ['v1/users'], 
       'pluralize' => false, 
       'tokens' => [ 
        '{id}' => '<id:\\w+>' 
       ] 
      ], 
      //Rutas usuario 
      'v1/login' => '/v1/users/login' 
     ],   
    ], 

risposta

0

È necessario collegare Cors filtro nel metodo behaviours() del controller (vedere come in official guide) con i seguenti condizioni:

  1. Cors filtro deve essere definito prima dei filtri di autenticazione/autorizzazione
  2. accesso aperto per tutti gli utenti all'azione option in AccessControl filtro

Nella tua situazione, UsersController potrebbero avere come behaviors() metodo:

public function behaviors() 
{ 
    return ArrayHelper::merge(
     [ 
      'cors' => [ 
       'class' => Cors::className(), 
      ], 
     ], 
     parent::behaviors(), 
     [ 
      'access' => [ 
       'class' => AccessControl::className(), 
       'rules' => [ 
        ['allow' => true, 'actions' => ['options']], 
       ] 
      ], 
     ] 
    ); 
} 
+0

@CreatorR Ho provato la tua soluzione ma non ha funzionato perché, penso, che non hai capito la mia domanda .. Loking al codice sorgente di resto ActiveController, vedo che un 'yii \ rest \ OptionsAction' l'azione è configurata per il metodo delle opzioni. C'è un modo per configurarlo che quando si chiama/login con POST chiama actionLogin e quando si chiama/login con OPTIONS allora chiama 'yii \ rest \ OptionsAction'? Qual è il modo migliore per farlo? Penso che questo sia quello che mi serve .. – edrian

+0

@edrian, sarebbe bello vedere le tue urlRegole di manager – CreatoR

+0

@CreatorR Ho aggiornato il post come richiesto – edrian

4

Di default la classe yii\rest\UrlRule applicherà quei modelli a qualsiasi endpoint:

'patterns' => [ 
    'PUT,PATCH {id}' => 'update', 
    'DELETE {id}' => 'delete', 
    'GET,HEAD {id}' => 'view', 
    'POST' => 'create', 
    'GET,HEAD' => 'index', 
    '{id}' => 'options', 
    '' => 'options', 
] 

Ciò significa che qualsiasi richiesta contenente verbi OPTIONS verrà reindirizzata a yii\rest\OptionsAction se il tuo loginAction è scritto all'interno di una classe che estende ActiveController.

Quello che suggerisco è quella di ignorare patterns lasciando i soli verbi usati come login azione non ha bisogno di nessuna delle altre azioni CRUD. Questo dovrebbe funzionare con il vostro caso:

'rules' => [ 
    [ 
     'class' => 'yii\rest\UrlRule', 
     'controller' => ['v1/users'], 
     'pluralize' => false, 
     'tokens' => [ 
      '{id}' => '<id:\\w+>' 
     ] 
    ], 
    [ 
     'class' => 'yii\rest\UrlRule', 
     'controller' => ['v1/login' => '/v1/users/login'], 
     'patterns' => [ 
      'POST' => 'login', 
      '' => 'options', 
     ] 
    ] 
], 

NOTA: la soluzione da @CreatoR è anche un requisito qui ed esattamente come lo ha fatto senza definire chiavi. altrimenti i verbi OPZIONI saranno rifiutati se non autentificati.


Nel caso in cui il vostro login azione viene definita sotto estendendo una classe yii\rest\Controller direttamente invece di passare attraverso yii\rest\ActiveController (che dovrebbe essere adeguata per le azioni di autenticazione in quanto non v'è alcuna CRUD necessario qui) quindi le stesse regole configurazioni dovrebbero funzionare bene, ma è necessario aggiungere manualmente i actionOptions al codice:

// grabbed from yii\rest\OptionsAction with a little work around 
private $_verbs = ['POST','OPTIONS']; 

public function actionOptions() 
{ 
    if (Yii::$app->getRequest()->getMethod() !== 'OPTIONS') { 
     Yii::$app->getResponse()->setStatusCode(405); 
    } 
    $options = $this->_verbs; 
    Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $options)); 
} 
2

ho risolto problema estendendo Co rs classe di filtro:

use Yii; 
use yii\filters\Cors; 

class CorsCustom extends Cors 

{ 
    public function beforeAction($action) 
    { 
     parent::beforeAction($action); 

     if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') { 
      Yii::$app->getResponse()->getHeaders()->set('Allow', 'POST GET PUT'); 
      Yii::$app->end(); 
     } 

     return true; 
    } 
} 

e poi

public function behaviors() 
{ 
    $behaviors = parent::behaviors(); 
    unset($behaviors['authenticator']); 
    $behaviors['corsFilter'] = [ 
     'class' => CorsCustom::className(), 
    ]; 
    $behaviors['authenticator'] = [ 
     'class' => HttpBearerAuth::className(), 
     'optional' => ['login'] 
    ]; 
    return $behaviors; 
} 
+0

Quindi, dove aggiungerai questa personalizzazione Cors al controller rimanente –

+0

Ho aggiornato la risposta –

0
'rules' => [ 
    [ 
     'class' => 'yii\rest\UrlRule', 
     'controller' => ['v1/users'], 
     'pluralize' => false, 
     'tokens' => [ 
      '{id}' => '<id:\\w+>' 
     ] 
    ], 
    [ 
     'class' => 'yii\rest\UrlRule', 
     'controller' => ['v1/login' => '/v1/users/login'], 
     'patterns' => [ 
      'POST' => 'login', 
      'OPTIONS' => 'options', 
     ] 
    ] 
], 
1

Ho avuto questo stesso problema.

Ecco come ho riparato:

ho aggiunto un parametro extraPatterns alla mia regola, in questo modo:

'urlManager' => [ 
     'enablePrettyUrl' => true, 
     'showScriptName' => false, 
     'rules' => [ 
      [ 
       'class' => 'yii\rest\UrlRule', 
       'pluralize' => false, 
       'controller' => [ 
        'athlete', 
        'admin', 
        'address', 
        'program' 
       ], 
       'extraPatterns' => [ 
        'OPTIONS <action:\w+>' => 'options' 
       ] 
      ] 
     ], 
    ], 

In questo modo, l'azione options verrà chiamato per ogni azione personalizzata che ho in uno di questi controller.

Problemi correlati