Yii2 Rest – индивидуальное действие и метод OPTIONS

У меня возникли проблемы со следующим действием «/ login» в моем классе UsersController

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

Ситуация заключается в том, что я использую метод POST для входа в систему, и я вызываю этот маршрут из другого домена, поэтому передняя библиотека сначала пытается вызвать / войти в маршрут с помощью метода OPTIONS, чтобы проверить, разрешено или не разрешено / Войти с POST ..

Проблема в том, что встроенные функции yii2 останутся в ActiveController только для / users и / users / {id}

Если я вручную добавлю этот / логин, чтобы быть доступным как в POST, так и в OPTIONS через действия verbFilter, тогда yii пытается фактически вызвать действие входа с запросом OPTIONS. Я имею в виду, он пытается выполнить вход в систему. Конечно, это невозможно, поскольку он не отправляет поля электронной почты и паролей, но я вижу ошибку в файле журнала.

Итак, мой вопрос: … Есть ли способ правильно настроить эти «настраиваемые» маршруты и сделать OPTIONS прозрачным? Поскольку я ожидаю, что действие входа не будет выполнено при вызове с помощью OPTIONS, но вместо этого вернет непосредственно заголовки методов, разрешенных OPTIONS.

Обновить информацию: Добавлены правила менеджера 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' ], ], 

По умолчанию класс yii\rest\UrlRule будет применять эти шаблоны к любой конечной точке:

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

Это означает, что любой запрос, содержащий команды OPTIONS, будет перенаправлен на yii\rest\OptionsAction если ваш loginAction написан внутри класса, расширяющего ActiveController .

Я предлагаю переопределить patterns , оставив единственные используемые глаголы, поскольку ваше действие входа не требует каких-либо других действий CRUD. это должно работать с вашим делом:

 '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', ] ] ], 

ПРИМЕЧАНИЕ. Решение @CreatoR также является требованием здесь и точно так же, как и он, без определения ключей. иначе аргументы OPTIONS будут отклонены, если не будут аутентифицированы.


В случае, если ваше действие для входа определено под классом, расширяющим yii\rest\Controller напрямую, а не через yii\rest\ActiveController (что должно быть подходящим для действий аутентификации, поскольку здесь нет CRUD), то те же правила config должны работать отлично, но вам нужно вручную добавить actionOptions в свой код:

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

Я решил проблему, расширив класс фильтра Cors:

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

а потом

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

У меня была такая же проблема.

Вот как я это исправил:

Я добавил параметр extraPatterns для своего правила, например:

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

Таким образом, действие options будет вызываться для каждого пользовательского действия, которое у меня есть в любом из этих контроллеров.

Вам необходимо присоединить фильтр Cors в методе behaviours() вашего контроллера behaviours() (см. Как в официальном руководстве ) со следующими условиями:

  1. Фильтр Cors должен быть определен до фильтров аутентификации / авторизации
  2. Открыть доступ для всех пользователей к действию в фильтре AccessControl

В вашей ситуации у UsersController может быть такое behaviors() :

 public function behaviors() { return ArrayHelper::merge( [ 'cors' => [ 'class' => Cors::className(), ], ], parent::behaviors(), [ 'access' => [ 'class' => AccessControl::className(), 'rules' => [ ['allow' => true, 'actions' => ['options']], ] ], ] ); } 
 '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', ] ] ],