structure-filters.md 21.2 KB
Newer Older
1 2 3
Фильтры
=======

4 5 6 7
Фильтры — это объекты, которые могут запускаться как перед так и после [действий контроллера](structure-controllers.md#actions).
Например, фильтр управления доступом может запускаться перед действиями удостовериться, что запросившему их пользователю
разрешен доступ; фильтр сжатия содержимого может запускаться после действий для сжатия содержимого ответа перед отправкой
его конечному пользователю.
8

9 10
Фильтр может состоять из *пре-фильтра* (фильтрующая логика применяется *перед* действиями) и/или
*пост-фильтра* (логика, применяемая *после* действий).
11

12
## Использование фильтров <span id="using-filters"></span>
13

14 15 16
Фильтры являются особым видом [поведений](concept-behaviors.md). Их использование ничем не отличается от
[использования поведений](concept-behaviors.md#attaching-behaviors). Вы можете объявлять фильтры в классе контроллера
путём перекрытия метода [[yii\base\Controller::behaviors()|behaviors()]]:
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

```php
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');
            },
        ],
    ];
}
```

34 35 36 37
По умолчанию фильтры, объявленные в классе контроллера, будут применяться ко *всем* его действиям. Тем не менее, вы можете
явно указать и конкретные действия задав свойство [[yii\base\ActionFilter::only|only]]. В примере выше фильтр `HttpCache`
применяется только к действиям `index` и `view`. Вы можете настроить свойство [[yii\base\ActionFilter::except|except]]
чтобы указать действия, к которым фильтр применяться не должен.
38

39 40 41
Кроме контроллеров, можно объявлять фильтры в [модуле](structure-modules.md) или в [приложении](structure-applications.md).
В этом случае они применяются ко *всем* действиям контроллеров, находящихся в этом модуле или приложении если не заданы
свойства [[yii\base\ActionFilter::only|only]] и [[yii\base\ActionFilter::except|except]] как было описано выше.
42

43 44 45
> Примечание: При объявлении фильтров в модулях или приложениях, следует использовать [маршруты](structure-controllers.md#routes)
  вместо идентификаторов действий в свойствах [[yii\base\ActionFilter::only|only]] и [[yii\base\ActionFilter::except|except]]
  так как сами по себе, идентификаторы действий не могут полностью идентифицировать действие в контексте модуля или приложения.
46

47
Когда несколько фильтров указываются для одного действия, они применяются согласно следующим правилам:
48 49 50 51 52 53 54 55 56 57 58 59 60

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


61
## Создание фильтров <span id="creating-filters"></span>
62

63 64 65 66 67
При создании нового фильтра действия, необходимо наследоваться от [[yii\base\ActionFilter]] и переопределить методы
[[yii\base\ActionFilter::beforeAction()|beforeAction()]] и/или [[yii\base\ActionFilter::afterAction()|afterAction()]].
Первый из них будет вызыван перед выполнением действия, а второй после. Возвращаемое
[[yii\base\ActionFilter::beforeAction()|beforeAction()]] значение определяет, будет ли действие выполняться или нет.
Если вернётся `false`, то оставшиеся фильтры не будут применены и действие выполнено не будет.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

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

```php
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);
    }
}
```


97
## Стандартные фильтры <span id="core-filters"></span>
98

99 100
Yii предоставляет набор часто используемых фильтров, которые находятся, в основном, в пространстве имен `yii\filters`.
Далее вы будете кратко ознакомлены с ними.
101 102


103
### [[yii\filters\AccessControl|AccessControl]] <span id="access-control"></span>
104

105 106 107 108 109
Фильтр `AccessControl` обеспечивает простое управление доступом, основанное на наборе правил [[yii\filters\AccessControl::rules|rules]].
В частности, перед тем как действие начинает выполнение, фильтр `AccessControl` проверяет список указанных правил, пока не
найдёт соответствующее текущему контексту переменных (таких как IP адрес пользователя, статус аутентификации и так далее).
Найденное правило указывает, разрешить или запретить выполнение запрошенного действия. Если ни одно из правил не подходит,
то доступ будет запрещён.
110

111 112
В следующем примере авторизованным пользователям разрешен доступ к действиям `create` и `update`, в то время как всем
другим пользователям доступ запрещён.
113 114 115 116 117 118 119 120 121 122 123

```php
use yii\filters\AccessControl;

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'only' => ['create', 'update'],
            'rules' => [
124
                // разрешаем аутентифицированным пользователям
125 126 127 128
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
129
                // всё остальное по умолчанию запрещено
130 131 132 133 134 135
            ],
        ],
    ];
}
```

136
Более подробно об управлении доступом вы можете прочитать в разделе [Авторизация](security-authorization.md).
137 138


139
### Фильтр метода аутентификации<span id="auth-method-filters"></span>
140

141
Фильтр метода аутентификации используется для аутентификации пользователя различными способами, такими как
142 143 144
[HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication), [OAuth 2](http://oauth.net/2/).
Классы данных фильтров находятся в пространстве имён `yii\filters\auth`.

145 146 147 148
Следующий пример показывает, как использовать [[yii\filters\auth\HttpBasicAuth]] для аутентификации пользователя с помощью
токена доступа, основанного на методе basic HTTP auth. Обратите внимание, что для того чтобы это работало, ваш класс
[[yii\web\User::identityClass|user identity class]] должен реализовывать метод
[[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]].
149 150 151 152 153 154 155 156 157 158 159 160 161 162

```php
use yii\filters\auth\HttpBasicAuth;

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

163
Фильтры метода аутентификации часто используются при реализации RESTful API. Более подробную информацию о технологии 
164 165 166
RESTful, смотрите в разделе [Authentication](rest-authentication.md).


167
### [[yii\filters\ContentNegotiator|ContentNegotiator]] <span id="content-negotiator"></span>
168

169 170
ContentNegotiator поддерживает согласование формата ответа и языка приложения. Он пытается определить формат ответа
и/или язык, путём проверки `GET` параметров и HTTP заголовка `Accept`.
171

172 173
В примере ниже, ContentNegotiator сконфигурирован чтобы поддерживать форматы ответа JSON и XML, а также Английский (США)
и Немецкий языки.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

```php
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',
            ],
        ],
    ];
}
```

197 198 199 200
Часто требуется, чтобы форматы ответа и языки приложения были определены как можно раньше в его
[жизненном цикле](structure-applications.md#application-lifecycle). По этой причине, ContentNegotiator разработан так, что
помимо фильтра может использоваться как [компонент предварительной загрузки](structure-applications.md#bootstrap). Например,
вы можете настроить его в [конфигурации приложения](structure-applications.md#application-configurations):
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

```php
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',
            ],
        ],
    ],
];
```

223 224
> Информация: В случае, если предпочтительный тип содержимого и язык не могут быть определены из запроса, будут
  использованы первый формат и язык, описанные в [[formats]] и [[languages]].
225 226 227



228
### [[yii\filters\HttpCache|HttpCache]] <span id="http-cache"></span>
229

230
Фильтр HttpCache реализовывает кэширование на стороне клиента, используя HTTP заголовки `Last-Modified` и `Etag`:
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

```php
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');
            },
        ],
    ];
}
```

250
Подробнее об использовании HttpCache можно прочитать в разделе [HTTP Кэширование](caching-http.md).
251 252


253
### [[yii\filters\PageCache|PageCache]] <span id="page-cache"></span>
254

255 256 257
Фильтр PageCache реализует кэширование целых страниц на стороне сервера. В следующем примере PageCache применяется только
в действии `index` для кэширования всей страницы в течение не более чем 60 секунд или пока количество записей в таблице `post`
не изменится. Он также хранит различные версии страницы в зависимости от выбранного языка приложения.
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

```php
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,
            ]
        ],
    ];
}
```

282
Подробнее об использовании PageCache читайте в разделе [Кэширование страниц](caching-page.md).
283 284


285
### [[yii\filters\RateLimiter|RateLimiter]] <span id="rate-limiter"></span>
286

287 288 289
Ограничитель количества запросов в единицу времени *(RateLimiter)* реализует алгоритм ограничения запросов, основанный на
[алгоритме leaky bucket](http://en.wikipedia.org/wiki/Leaky_bucket). В основном, он используется при создании RESTful API.
Подробнее об использовании данного фильтра пожно прочитать в разделе [Ограничение запросов](rest-rate-limiting.md).
290 291


292
### [[yii\filters\VerbFilter|VerbFilter]] <span id="verb-filter"></span>
293

294 295 296
Фильтр по типу запроса *(VerbFilter)* проверяет, разрешено ли запросам HTTP выполнять затребованные ими действия.
Если нет, то будет выброшено исключение HTTP с кодом 405. В следующем примере в фильтре по типу запроса указан обычный
набор разрешённых методов запроса при выполнения CRUD операций.
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

```php
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'],
            ],
        ],
    ];
}
```

318
### [[yii\filters\Cors|Cors]] <span id="cors"></span>
319

320 321 322 323 324
Совместное использование разными источниками [CORS](https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS) - это
механизм, который позволяет использовать различные ресурсы (шрифты, скрипты, и т.д.) с отличных от основного сайта доменов.
В частности, AJAX вызовы JavaScript могут использовать механизм XMLHttpRequest. В противном случае, такие "междоменные"
запросы были бы запрещены из-за политики безопасности same origin.
CORS задаёт способ взаимодействия сервера и браузера, определяющий возможность делать междоменные запросы.
325

326 327
Фильтр [[yii\filters\Cors|Cors filter]] следует определять перед фильтрами Аутентификации / Авторизации, для того чтобы
быть уверенными, что заголовки CORS будут всегда посланы.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

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

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

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

345 346 347 348 349 350 351 352
* `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`.
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
* `cors['Access-Control-Max-Age']`: определяет *срок жизни запроса, перед его началом*. По умолчанию `86400`.

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

```php
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` для действия  `login` может быть сделано так :

```php
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());
}
```