Контроллеры
После создания классов ресурсов и настройки способа форматирования ресурсных данных следующим шагом является создание действий контроллеров для предоставления ресурсов конечным пользователям через RESTful API.
В Yii есть два базовых класса контроллеров для упрощения вашей работы по созданию RESTful-действий: [[yii\rest\Controller]] и [[yii\rest\ActiveController]]. Разница между этими двумя контроллерами в том, что у последнего есть набор действий по умолчанию, который специально создан для работы с ресурсами, представленными Active Record. Так что если вы используете Active Record и вас устраивает предоставленный набор встроенных действий, вы можете унаследовать классы ваших контроллеров от [[yii\rest\ActiveController]], что позволит вам создать полноценные RESTful API, написав минимум кода.
[[yii\rest\Controller]] и [[yii\rest\ActiveController]] имеют следующие возможности, некоторые из которых будут подробно описаны в следующих разделах:
- Проверка HTTP-метода;
- Согласование содержимого и форматирование данных;
- Аутентификация;
- Ограничение частоты запросов.
[[yii\rest\ActiveController]], кроме того, предоставляет следующие возможности:
- Набор наиболее часто используемых действий:
index
,view
,create
,update
,delete
иoptions
; - Авторизация пользователя для запрашиваемых действия и ресурса.
Создание классов контроллеров
При создании нового класса контроллера в имени класса обычно используется название типа ресурса в единственном числе. Например, контроллер, отвечающий за предоставление информации о пользователях, можно назвать UserController
.
Создание нового действия похоже на создание действия для Web-приложения. Единственное отличие в том, что в RESTful-действиях вместо рендера результата в представлении с помощью вызова метода render()
вы просто возвращаете данные. Выполнение преобразования исходных данных в запрошенный формат ложится на [[yii\rest\Controller::serializer|сериализатор]] и [[yii\web\Response|объект ответа]]. Например:
public function actionView($id)
{
return User::findOne($id);
}
Фильтры
Большинство возможностей RESTful API, предоставляемых [[yii\rest\Controller]], реализовано на основе фильтров. В частности, следующие фильтры будут выполняться в том порядке, в котором они перечислены:
- [[yii\filters\ContentNegotiator|contentNegotiator]]: обеспечивает согласование содержимого, более подробно описан в разделе Форматирование ответа;
- [[yii\filters\VerbFilter|verbFilter]]: обеспечивает проверку HTTP-метода;
- [[yii\filters\auth\AuthMethod|authenticator]]: обеспечивает аутентификацию пользователя, более подробно описан в разделе Аутентификация;
- [[yii\filters\RateLimiter|rateLimiter]]: обеспечивает ограничение частоты запросов, более подробно описан в разделе Ограничение частоты запросов.
Эти именованные фильтры объявлены в методе [[yii\rest\Controller::behaviors()|behaviors()]]. Вы можете переопределить этот метод для настройки отдельных фильтров, отключения каких-либо из них или для добавления ваших собственных фильтров. Например, если вы хотите использовать только базовую HTTP-аутентификацию, вы можете написать такой код:
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
CORS
Добавление фильтра совместного использования ресурсов между источниками в контроллер немного сложнее, чем добавление других фильтров, описанных выше, поскольку фильтр CORS должен применяться перед методами аутентификации и, следовательно, требует немного другого подхода по сравнению с другими фильтрами. Также аутентификация должна быть отключена для запросов CORS Preflight, чтобы браузер мог безопасно определить, можно ли сделать запрос заранее без необходимости отправки учетных данных аутентификации. Ниже приведен код, необходимый для добавления фильтра [[yii\filters\Cors]] в существующий контроллер, который выходит из [[yii\rest\ActiveController]]:
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
// remove authentication filter
$auth = $behaviors['authenticator'];
unset($behaviors['authenticator']);
// add CORS filter
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::className(),
];
// re-add authentication filter
$behaviors['authenticator'] = $auth;
// avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
$behaviors['authenticator']['except'] = ['options'];
return $behaviors;
}
Наследование от ActiveController
Если ваш класс контроллера наследуется от [[yii\rest\ActiveController]], вам следует установить значение его свойства [[yii\rest\ActiveController::modelClass|modelClass]] равным имени класса ресурса, который вы планируете обслуживать с помощью этого контроллера. Класс ресурса должен быть унаследован от [[yii\db\ActiveRecord]].
Настройка действий
По умолчанию [[yii\rest\ActiveController]] предоставляет набор из следующих действий:
- [[yii\rest\IndexAction|index]]: постраничный список ресурсов;
- [[yii\rest\ViewAction|view]]: возвращает подробную информацию об указанном ресурсе;
- [[yii\rest\CreateAction|create]]: создание нового ресурса;
- [[yii\rest\UpdateAction|update]]: обновление существующего ресурса;
- [[yii\rest\DeleteAction|delete]]: удаление указанного ресурса;
- [[yii\rest\OptionsAction|options]]: возвращает поддерживаемые HTTP-методы.
Все эти действия объявляются в методе [[yii\rest\ActiveController::actions()|actions()]]. Вы можете настроить эти действия или отключить какие-то из них, переопределив метод actions()
, как показано ниже:
public function actions()
{
$actions = parent::actions();
// отключить действия "delete" и "create"
unset($actions['delete'], $actions['create']);
// настроить подготовку провайдера данных с помощью метода "prepareDataProvider()"
$actions['index']['prepareDataProvider'] = [$this, 'prepareDataProvider'];
return $actions;
}
public function prepareDataProvider()
{
// подготовить и вернуть провайдер данных для действия "index"
}
Чтобы узнать, какие опции доступны для настройки классов отдельных действий, обратитесь к соответствующим разделам справочника классов.
Выполнение контроля доступа
При предоставлении ресурсов через RESTful API часто бывает нужно проверять, имеет ли текущий пользователь разрешение на доступ к запрошенному ресурсу (или ресурсам) и манипуляцию им (или ими). Для [[yii\rest\ActiveController]] эта задача может быть решена переопределением метода [[yii\rest\ActiveController::checkAccess()|checkAccess()]] следующим образом:
/**
* Проверяет права текущего пользователя.
*
* Этот метод должен быть переопределен, чтобы проверить, имеет ли текущий пользователь
* право выполнения указанного действия над указанной моделью данных.
* Если у пользователя нет доступа, следует выбросить исключение [[ForbiddenHttpException]].
*
* @param string $action ID действия, которое надо выполнить
* @param \yii\base\Model $model модель, к которой нужно получить доступ. Если `null`, это означает, что модель, к которой нужно получить доступ, отсутствует.
* @param array $params дополнительные параметры
* @throws ForbiddenHttpException если у пользователя нет доступа
*/
public function checkAccess($action, $model = null, $params = [])
{
// проверить, имеет ли пользователь доступ к $action и $model
// выбросить ForbiddenHttpException, если доступ следует запретить
if ($action === 'update' || $action === 'delete') {
if ($model->author_id !== \Yii::$app->user->id)
throw new \yii\web\ForbiddenHttpException(sprintf('You can only %s articles that you\'ve created.', $action));
}
}
Метод checkAccess()
будет вызван действиями по умолчанию контроллера [[yii\rest\ActiveController]]. Если вы создаёте новые действия и хотите в них выполнять контроль доступа, вы должны вызвать этот метод явно в своих новых действиях.
Tip: вы можете реализовать метод
checkAccess()
с помощью "Контроля доступа на основе ролей" (RBAC).
Заберите ссылку на статью к себе, чтобы потом легко её найти!
Раз уж досюда дочитали, то может может есть желание рассказать об этом месте своим друзьям, знакомым и просто мимо проходящим?
Не надо себя сдерживать! ;)