Фильтры

Фильтры - это объекты, которые запускаются до или после действий контроллера. Например, фильтр управления доступом может выполняться перед действиями, чтобы гарантировать, что им разрешен доступ к конкретным конечным пользователям; Фильтр сжатия содержимого может выполняться после действий по сжатию содержимого ответа до отправки его конечным пользователям.

Фильтр может состоять из предварительного фильтра (логика фильтрации, применяемого перед действиями) или постфильтра (логика применяется после действий).

Использование фильтров

Фильтры по существу являются особым видом поведения. Поэтому использование фильтров аналогично использованию поведений. Вы можете объявить фильтры в классе контроллера, переопределив свой метод behaviors() следующим образом:

public function behaviors()
{
    return [
        [
            'class' => 'yii\filters\HttpCache',
            'only' => ['index', 'view'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('user')->max('updated_at');
            },
        ],
    ];
}

По умолчанию фильтры, объявленные в классе контроллера, будут применяться ко всем действиям в этом контроллере. Однако вы можете явно указать, к каким действиям должен применяться фильтр, настроив только одно свойство. В приведенном выше примере фильтр HttpCache применяется только к действиям index и view. Вы также можете настроить свойство except на черный список, чтобы некоторые действия были отфильтрованы.

Помимо контроллеров, вы также можете объявлять фильтры в модуле или приложении. Когда вы сделаете это, фильтры будут применены ко всем действиям контроллера, принадлежащим этому модулю или приложению, если только вы не настроите фильтры только и за исключением свойств, как описано выше.

Если несколько фильтров настроены для одного действия, они применяются в соответствии с правилами, описанными ниже:

  • Предварительная фильтрация
    • Применение фильтров, объявленных в приложении, в порядке их перечисления в behaviors().
    • Примените фильтры, объявленные в модуле, в порядке, указанном в behaviors().
    • Применить фильтры, объявленные в контроллере, в порядке их перечисления в behaviors().
    • Если какой-либо из фильтров отменит выполнение действия, фильтры (как предварительные фильтры, так и пост-фильтры) после него не будут применены.
  • Выполнение действия, если оно прошло предварительную фильтрацию.
  • Послефильтрация
    • Применить фильтры, объявленные в контроллере, в обратном порядке, они перечислены в behaviors().
    • Применяйте фильтры, объявленные в модуле, в обратном порядке, они перечислены в behaviors().
    • Применить фильтры, объявленные в приложении, в обратном порядке, они перечислены в behaviors().

Создание фильтров

Чтобы создать новый фильтр действий, нужно перейти от yii\base\ActionFilter и переопределить методы beforeAction() или afterAction(). Первый будет выполнен до запуска действия, а второй после выполнения действия. Возвращаемое значение beforeAction() определяет, должно ли выполняться действие или нет. Если это false, фильтры после этого будут пропущены, и действие не будет выполнено.

В следующем примере показан фильтр, который регистрирует время выполнения действия:

namespace app\components;

use Yii;
use yii\base\ActionFilter;

class ActionTimeFilter extends ActionFilter
{
    private $_startTime;

    public function beforeAction($action)
    {
        $this->_startTime = microtime(true);
        return parent::beforeAction($action);
    }

    public function afterAction($action, $result)
    {
        $time = microtime(true) - $this->_startTime;
        Yii::trace("Action '{$action->uniqueId}' spent $time second.");
        return parent::afterAction($action, $result);
    }
}

Основные фильтры

Yii предоставляет набор часто используемых фильтров, найденных, главным образом, в пространстве имен yii\filters. Ниже мы кратко представим эти фильтры.

Контроль доступа

AccessControl обеспечивает простой контроль доступа на основе набора правил. В частности, перед выполнением действия AccessControl будет проверять перечисленные правила и найти первый, соответствующий текущим контекстным переменным (например, IP-адрес пользователя, статус входа пользователя и т.д.). Правило сопоставления будет определять, разрешать или запрещать Выполнение запрошенного действия. Если ни одно правило не совпадает, доступ будет запрещен.

В следующем примере показано, как предоставить пользователям, прошедшим проверку подлинности, доступ к действиям create и update, не позволяя всем другим пользователям получать доступ к этим двум действиям.

use yii\filters\AccessControl;

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['create', 'update'],
            'rules' => [
                // разрешить аутентифицированным пользователям
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                // все остальное по умолчанию запрещено
            ],
        ],
    ];
}

Фильтры метода проверки подлинности

Фильтры метода аутентификации используются для аутентификации пользователя с использованием различных методов, таких как HTTP Basic Auth, OAuth 2. Эти классы фильтров находятся в пространстве имен yii\filters\auth.

В следующем примере показано, как можно использовать yii\filters\auth\HttpBasicAuth для проверки подлинности пользователя с использованием токена доступа на основе метода HTTP Basic Auth. Обратите внимание, что для того, чтобы это сработало, класс идентификации пользователя должен реализовать метод findIdentityByAccessToken().

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    return [
        'basicAuth' => [
            'class' => HttpBasicAuth::className(),
        ],
    ];
}

Фильтры метода аутентификации обычно используются при реализации API RESTful.

ContentNegotiator

ContentNegotiator поддерживает согласование формата ответа и согласование языка приложения. Он попытается определить формат ответа или язык, изучив параметры GET и Accept HTTP header.

В следующем примере ContentNegotiator настроен на поддержку форматов ответов JSON и XML, а также на английском (США) и немецком языках.

use yii\filters\ContentNegotiator;
use yii\web\Response;

public function behaviors()
{
    return [
        [
            'class' => ContentNegotiator::className(),
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ];
}

Форматы ответов и языки часто должны быть определены намного раньше на протяжении жизненного цикла приложения. По этой причине ContentNegotiator разработан таким образом, что он также может использоваться как компонент начальной загрузки, кроме того, что используется как фильтр. Например, вы можете настроить его в конфигурации приложения следующим образом:

use yii\filters\ContentNegotiator;
use yii\web\Response;

[
    'bootstrap' => [
        [
            'class' => ContentNegotiator::className(),
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
                'application/xml' => Response::FORMAT_XML,
            ],
            'languages' => [
                'en-US',
                'de',
            ],
        ],
    ],
];

HttpCache

HttpCache реализует кэширование на стороне клиента, используя HTTP-заголовки Last-Modified и Etag. Например:

use yii\filters\HttpCache;

public function behaviors()
{
    return [
        [
            'class' => HttpCache::className(),
            'only' => ['index'],
            'lastModified' => function ($action, $params) {
                $q = new \yii\db\Query();
                return $q->from('user')->max('updated_at');
            },
        ],
    ];
}

PageCache

PageCache реализует кэширование целых страниц на стороне сервера. В следующем примере PageCache применяется к действию index для кэширования всей страницы в течение максимум 60 секунд или до изменения количества записей в таблице post. Он также хранит разные версии страницы в зависимости от выбранного языка приложения.

use yii\filters\PageCache;
use yii\caching\DbDependency;

public function behaviors()
{
    return [
        'pageCache' => [
            'class' => PageCache::className(),
            'only' => ['index'],
            'duration' => 60,
            'dependency' => [
                'class' => DbDependency::className(),
                'sql' => 'SELECT COUNT(*) FROM post',
            ],
            'variations' => [
                \Yii::$app->language,
            ]
        ],
    ];
}

RateLimiter

RateLimiter реализует алгоритм ограничения скорости, основанный на алгоритме отказоустойчивого сегмента. Он в основном используется при реализации RESTful API. 

VerbFilter

VerbFilter проверяет, разрешены ли методы запроса HTTP запрошенными действиями. Если это не разрешено, он будет генерировать исключение HTTP 405. В следующем примере VerbFilter объявлен для указания типичного набора разрешенных методов запроса для действий CRUD.

use yii\filters\VerbFilter;

public function behaviors()
{
    return [
        'verbs' => [
            'class' => VerbFilter::className(),
            'actions' => [
                'index'  => ['get'],
                'view'   => ['get'],
                'create' => ['get', 'post'],
                'update' => ['get', 'put', 'post'],
                'delete' => ['post', 'delete'],
            ],
        ],
    ];
}

CORS

Совместное использование ресурсов CORS - это механизм, который позволяет запрашивать много ресурсов (например, шрифтов, JavaScript и т. д.) На веб-странице из другого домена вне домена, из которого был создан ресурс. В частности, вызовы AJAX в JavaScript могут использовать механизм XMLHttpRequest. Такие «междоменные» запросы в противном случае запрещались бы веб-браузерами в соответствии с той же политикой безопасности происхождения. CORS определяет, как браузер и сервер могут взаимодействовать, чтобы определить, разрешать или не разрешать перекрестный запрос.

Фильтр Cors должен быть определен перед фильтрами Authentication/Authorization, чтобы удостовериться, что заголовки CORS будут всегда отправляться.

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::className(),
        ],
    ], parent::behaviors());
}

Также проверьте раздел на контроллерах REST, если вы хотите добавить фильтр CORS в класс yii\rest\ActiveController в вашем API.

Фильтрация Cors может быть настроена с использованием свойства $cors.

  • cors ['Origin']: массив, используемый для определения допустимого происхождения. Может быть ['*'] (все) или ['http://www.myserver.net', 'http://www.myotherserver.com']. По умолчанию ['*'].
  • cors ['Access-Control-Request-Method']: массив допустимых глаголов типа ['GET', 'OPTIONS', 'HEAD']. По умолчанию используется значение ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].
  • cors ['Access-Control-Request-Headers']: массив допустимых заголовков. Может быть ['*'] всеми заголовками или конкретными ['X-Request-With']. По умолчанию ['*'].
  • cors ['Access-Control-Allow-Credentials']: определить, может ли текущий запрос быть выполнен с использованием учетных данных. Может быть true, false или null (не установлено). Значение по умолчанию: null.
  • cors ['Access-Control-Max-Age']: определение срока действия предполетного запроса. По умолчанию: 86400.

Например, разрешая CORS для происхождения: http://www.myserver.net с методом GET, HEAD и OPTIONS:

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::className(),
            'cors' => [
                'Origin' => ['http://www.myserver.net'],
                'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
            ],
        ],
    ], parent::behaviors());
}

Вы можете настраивать заголовки CORS, переопределяя параметры по умолчанию для каждого действия. Например, добавление учетных данных Access-Control-Allow-Credentials для действия входа может быть сделано следующим образом:

use yii\filters\Cors;
use yii\helpers\ArrayHelper;

public function behaviors()
{
    return ArrayHelper::merge([
        [
            'class' => Cors::className(),
            'cors' => [
                'Origin' => ['http://www.myserver.net'],
                'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'],
            ],
            'actions' => [
                'login' => [
                    'Access-Control-Allow-Credentials' => true,
                ]
            ]
        ],
    ], parent::behaviors());
}