Yiiフィルターの紹介
フィルターは、コントローラーのアクションの前または後に実行するように構成できるコードの一部です。たとえば、アクセス制御フィルターは、要求されたアクションを実行する前にユーザーが認証されていることを確認するために実行されます。パフォーマンス フィルターは、コントローラーの実行にかかる時間を測定するために使用できます。
アクションには複数のフィルターを含めることができます。フィルタは、フィルタ リストに表示される順序で実行されます。フィルターにより、アクションや後続の他のフィルターの実行が妨げられる場合があります。
フィルターを記述するには 2 つの方法があります:
どのような種類のフィルターを使用する場合でも、コントローラーでコントローラーのパブリック関数 filters() メソッドをオーバーライドして、どのフィルターがどのアクションに作用するかを設定する必要があります。
メソッドベースのフィルター
メソッドベースのフィルターを作成するには、次の 3 つの手順が必要です:
コントローラーにアクションを書きます;
コントローラーにフィルター関数を記述します。 function filterAccessControl(); のように、関数名の前にフィルターを付ける必要があります。
親クラス CController の filters() メソッドを書き換えて、フィルターとアクションの関係を定義します
例:
リーリー
カスタムフィルタークラス
フィルター クラスをカスタマイズするには、別のフィルター クラスを作成し、CFilter クラスを継承し、CFilter クラスのいくつかのメソッドをオーバーライドする必要があります。 CFilter クラスのコードを見てみましょう。このクラスにはそれほど多くのコードはありませんが、それでも理解しやすいです。カスタムフィルターの例:
リーリー
カスタムフィルターとアクション間のバインディング関係をコントローラーに登録します:
リーリー
フィルター: TestFilter をカスタマイズしました。これは、CFilter クラスを継承し、CFilter クラスの 2 つの主要メソッドである preFilter (プレコントローラー、アクションが実行される前に実行されます) と postFilter (ポストコントローラー、アクションの実行後に実行されます) をオーバーライドします。 )。
2つのコントローラーの実行シーケンス
上記で作成したカスタム フィルター クラスを actionAdd にバインドすると、カスタム フィルターは親クラス CFilter から preFilter と postFilter という 2 つのメソッドを継承します。テスト後の実行順序は、CFilter::preFilter--------->UserController::actionAdd--------->CFilter::postFilter になります。
言い換えれば、フィルタリング操作はアクションの実行前後に実行できます。
それでは、記事の冒頭で「フィルターはアクションやその後の他のフィルターの実行を防ぐことができる」と書かれているのはなぜでしょうか?
CFilter::preFilter:
の公式コメントを読めばわかります。
@return boolean フィルタリングプロセスを続行し、アクションを実行するかどうか。
true; つまり、後続のアクションとポストフィルターがデフォルトで実行されます。カスタム フィルター クラスの場合は、CFilter::preFilter メソッドをオーバーライドして戻ります
false; 後続のアクションとフィルターの実行を防ぐことができます。
フィルターを使用する
コントローラー クラスのフィルターは、デフォルトでクラスのすべてのアクションに適用されます。 yiibaseActionFilter::only 属性を設定して、コントローラーが適用されるアクションを明示的に指定できます。 上記の例では、HttpCache フィルターはインデックス アクションとビュー アクションにのみ適用されます。 一部のアクションがフィルターを実行しないように yiibaseActionFilter::Except 属性を設定することもできます。
コントローラーに加えて、フィルターはモジュールまたはアプリケーション本体で宣言できます。 宣言後、フィルターの yiibaseActionFilter::only 属性と yiibaseActionFilter::Except 属性が上記のように設定されていない限り、フィルターはモジュールまたはアプリケーション本体に属するすべてのコントローラー アクションに適用されます。
補足: モジュールまたはアプリケーション本体でフィルターを宣言する場合は、 yiibaseActionFilter::only および yiibaseActionFilter::Except 属性でアクション ID の代わりにルートを使用します。これは、モジュールまたはアプリケーション本体でアクション ID を使用するだけでは、特定のアクションを一意に指定できないためです。 。 .
アクションに複数のフィルターがある場合、それらは次のルールに従って順番に実行されます:
アプリケーション本体のbehaviors()にリストされているフィルターを順番に実行します。
コントローラーのbehaviors()にリストされているフィルターを逆の順序で実行します。
继承 yii\base\ActionFilter 类并覆盖 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法来创建动作的过滤器,前者在动作执行之前执行,后者在动作执行之后执行。 yii\base\ActionFilter::beforeAction() 返回值决定动作是否应该执行, 如果为false,之后的过滤器和动作不会继续执行。 下面的例子申明一个记录动作执行时间日志的过滤器。 Yii提供了一组常用过滤器,在yii\filters命名空间下,接下来我们简要介绍这些过滤器。 1.yii\filters\AccessControl AccessControl提供基于yii\filters\AccessControl::rules规则的访问控制。 特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则, 来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。 如下示例表示表示允许已认证用户访问create 和 update 动作,拒绝其他用户访问这两个动作。 认证方法过滤器通过HTTP Basic Auth或OAuth 2 来认证一个用户,认证方法过滤器类在 yii\filters\auth 命名空间下。 如下示例表示可使用yii\filters\auth\HttpBasicAuth来认证一个用户,它使用基于HTTP基础认证方法的令牌。 注意为了可运行,yii\web\User::identityClass 类必须 实现 yii\web\IdentityInterface::findIdentityByAccessToken()方法。 认证方法过滤器通常在实现RESTful API中使用。 3.yii\filters\ContentNegotiator ContentNegotiator支持响应内容格式处理和语言处理。 通过检查 GET 参数和 Accept HTTP头部来决定响应内容格式和语言。 如下示例,配置ContentNegotiator支持JSON和XML响应格式和英语(美国)和德语。 HttpCache利用Last-Modified 和 Etag HTTP头实现客户端缓存。例如: PageCache实现服务器端整个页面的缓存。如下示例所示,PageCache应用在index动作, 缓存整个页面60秒或post表的记录数发生变化。它也会根据不同应用语言保存不同的页面版本。 RateLimiter 根据 漏桶算法 来实现速率限制。 7.yii\filters\VerbFilter VerbFilter检查请求动作的HTTP请求方式是否允许执行,如果不允许,会抛出HTTP 405异常。 如下示例,VerbFilter指定CRUD动作所允许的请求方式。 跨域资源共享 CORS 机制允许一个网页的许多资源(例如字体、JavaScript等) 这些资源可以通过其他域名访问获取。 特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,由于同源安全策略该跨域请求会被网页浏览器禁止. CORS定义浏览器和服务器交互时哪些跨域请求允许和禁止。 yii\filters\Cors 应在 授权 / 认证 过滤器之前定义,以保证CORS头部被发送。 例如,允许来源为 http://www.myserver.net 和方式为 GET, HEAD 和 OPTIONS 的CORS如下:
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);
}
}
核心过滤器
use yii\filters\AccessControl;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update'],
'rules' => [
// 允许认证用户
[
'allow' => true,
'roles' => ['@'],
],
// 默认禁止其他用户
],
],
];
}
2.认证方法过滤器
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
return [
'basicAuth' => [
'class' => HttpBasicAuth::className(),
],
];
}
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',
],
],
],
];
补充: 如果请求中没有检测到内容格式和语言,使用formats和languages第一个配置项。
4.yii\filters\HttpCache
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');
},
],
];
}
5.yii\filters\PageCache
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,
]
],
];
}
6.yii\filters\RateLimiter
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'],
],
],
];
}
8.yii\filters\Cors
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
],
], parent::behaviors());
}
Cors 可转为使用 cors 属性。
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 头部。例如,为login动作增加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());
}
興味があるかもしれない記事: