過(guò)濾器是?控制器 動(dòng)作?執(zhí)行之前或之后執(zhí)行的對(duì)象。 例如訪問(wèn)控制過(guò)濾器可在動(dòng)作執(zhí)行之前來(lái)控制特殊終端用戶是否有權(quán)限執(zhí)行動(dòng)作, 內(nèi)容壓縮過(guò)濾器可在動(dòng)作執(zhí)行之后發(fā)給終端用戶之前壓縮響應(yīng)內(nèi)容。
過(guò)濾器可包含 預(yù)過(guò)濾(過(guò)濾邏輯在動(dòng)作之前) 或 后過(guò)濾(過(guò)濾邏輯在動(dòng)作之后),也可同時(shí)包含兩者。
過(guò)濾器本質(zhì)上是一類特殊的?行為,所以使用過(guò)濾器和?使用 行為一樣。 可以在控制器類中覆蓋它的 yii\base\Controller::behaviors() 方法來(lái)申明過(guò)濾器,如下所示:
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');
},
],
];
}
控制器類的過(guò)濾器默認(rèn)應(yīng)用到該類的?所有?動(dòng)作,你可以配置yii\base\ActionFilter::only屬性明確指定控制器應(yīng)用到哪些動(dòng)作。 在上述例子中,HttpCache
?過(guò)濾器只應(yīng)用到index
和view
動(dòng)作。 也可以配置yii\base\ActionFilter::except屬性使一些動(dòng)作不執(zhí)行過(guò)濾器。
除了控制器外,可在?模塊或應(yīng)用主體?中申明過(guò)濾器。 申明之后,過(guò)濾器會(huì)應(yīng)用到所屬該模塊或應(yīng)用主體的?所有?控制器動(dòng)作, 除非像上述一樣配置過(guò)濾器的 yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性。
補(bǔ)充: 在模塊或應(yīng)用主體中申明過(guò)濾器,在yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性中使用路由?代替動(dòng)作ID, 因?yàn)樵谀K或應(yīng)用主體中只用動(dòng)作ID并不能唯一指定到具體動(dòng)作。.
當(dāng)一個(gè)動(dòng)作有多個(gè)過(guò)濾器時(shí),根據(jù)以下規(guī)則先后執(zhí)行:
behaviors()
列出的過(guò)濾器。behaviors()
列出的過(guò)濾器。behaviors()
列出的過(guò)濾器。behaviors()
列出的過(guò)濾器。behaviors()
列出的過(guò)濾器。behaviors()
列出的過(guò)濾器。繼承 yii\base\ActionFilter 類并覆蓋 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法來(lái)創(chuàng)建動(dòng)作的過(guò)濾器,前者在動(dòng)作執(zhí)行之前執(zhí)行,后者在動(dòng)作執(zhí)行之后執(zhí)行。 yii\base\ActionFilter::beforeAction() 返回值決定動(dòng)作是否應(yīng)該執(zhí)行, 如果為false,之后的過(guò)濾器和動(dòng)作不會(huì)繼續(xù)執(zhí)行。
下面的例子申明一個(gè)記錄動(dòng)作執(zhí)行時(shí)間日志的過(guò)濾器。
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提供了一組常用過(guò)濾器,在yii\filters
命名空間下,接下來(lái)我們簡(jiǎn)要介紹這些過(guò)濾器。
AccessControl提供基于yii\filters\AccessControl::rules規(guī)則的訪問(wèn)控制。 特別是在動(dòng)作執(zhí)行之前,訪問(wèn)控制會(huì)檢測(cè)所有規(guī)則并找到第一個(gè)符合上下文的變量(比如用戶IP地址、登錄狀態(tài)等等)的規(guī)則, 來(lái)決定允許還是拒絕請(qǐng)求動(dòng)作的執(zhí)行,如果沒(méi)有規(guī)則符合,訪問(wèn)就會(huì)被拒絕。
如下示例表示表示允許已認(rèn)證用戶訪問(wèn)create
?和?update
?動(dòng)作,拒絕其他用戶訪問(wèn)這兩個(gè)動(dòng)作。
use yii\filters\AccessControl;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update'],
'rules' => [
// 允許認(rèn)證用戶
[
'allow' => true,
'roles' => ['@'],
],
// 默認(rèn)禁止其他用戶
],
],
];
}
更多關(guān)于訪問(wèn)控制的詳情請(qǐng)參閱?授權(quán)?一節(jié)。
認(rèn)證方法過(guò)濾器通過(guò)HTTP Basic Auth或OAuth 2?來(lái)認(rèn)證一個(gè)用戶,認(rèn)證方法過(guò)濾器類在?yii\filters\auth
?命名空間下。
如下示例表示可使用yii\filters\auth\HttpBasicAuth來(lái)認(rèn)證一個(gè)用戶,它使用基于HTTP基礎(chǔ)認(rèn)證方法的令牌。 注意為了可運(yùn)行,yii\web\User::identityClass 類必須 實(shí)現(xiàn) yii\web\IdentityInterface::findIdentityByAccessToken()方法。
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
return [
'basicAuth' => [
'class' => HttpBasicAuth::className(),
],
];
}
認(rèn)證方法過(guò)濾器通常在實(shí)現(xiàn)RESTful API中使用,更多關(guān)于訪問(wèn)控制的詳情請(qǐng)參閱 RESTful?認(rèn)證?一節(jié)。
ContentNegotiator支持響應(yīng)內(nèi)容格式處理和語(yǔ)言處理。 通過(guò)檢查?GET
?參數(shù)和?Accept
?HTTP頭部來(lái)決定響應(yīng)內(nèi)容格式和語(yǔ)言。
如下示例,配置ContentNegotiator支持JSON和XML響應(yīng)格式和英語(yǔ)(美國(guó))和德語(yǔ)。
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',
],
],
];
}
在應(yīng)用主體生命周期過(guò)程中檢測(cè)響應(yīng)格式和語(yǔ)言簡(jiǎn)單很多, 因此ContentNegotiator設(shè)計(jì)可被引導(dǎo)啟動(dòng)組件調(diào)用的過(guò)濾器。 如下例所示可以將它配置在應(yīng)用主體配置。
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',
],
],
],
];
補(bǔ)充: 如果請(qǐng)求中沒(méi)有檢測(cè)到內(nèi)容格式和語(yǔ)言,使用formats和languages第一個(gè)配置項(xiàng)。
HttpCache利用Last-Modified
?和?Etag
?HTTP頭實(shí)現(xiàn)客戶端緩存。例如:
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');
},
],
];
}
更多關(guān)于使用HttpCache詳情請(qǐng)參閱?HTTP 緩存?一節(jié)。
PageCache實(shí)現(xiàn)服務(wù)器端整個(gè)頁(yè)面的緩存。如下示例所示,PageCache應(yīng)用在index
動(dòng)作, 緩存整個(gè)頁(yè)面60秒或post
表的記錄數(shù)發(fā)生變化。它也會(huì)根據(jù)不同應(yīng)用語(yǔ)言保存不同的頁(yè)面版本。
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,
]
],
];
}
更多關(guān)于使用PageCache詳情請(qǐng)參閱?頁(yè)面緩存?一節(jié)。
RateLimiter 根據(jù)?漏桶算法?來(lái)實(shí)現(xiàn)速率限制。 主要用在實(shí)現(xiàn)RESTful APIs,更多關(guān)于該過(guò)濾器詳情請(qǐng)參閱?Rate Limiting?一節(jié)。
VerbFilter檢查請(qǐng)求動(dòng)作的HTTP請(qǐng)求方式是否允許執(zhí)行,如果不允許,會(huì)拋出HTTP 405異常。 如下示例,VerbFilter指定CRUD動(dòng)作所允許的請(qǐng)求方式。
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?機(jī)制允許一個(gè)網(wǎng)頁(yè)的許多資源(例如字體、JavaScript等) 這些資源可以通過(guò)其他域名訪問(wèn)獲取。 特別是JavaScript's AJAX 調(diào)用可使用 XMLHttpRequest 機(jī)制,由于同源安全策略該跨域請(qǐng)求會(huì)被網(wǎng)頁(yè)瀏覽器禁止. CORS定義瀏覽器和服務(wù)器交互時(shí)哪些跨域請(qǐng)求允許和禁止。
yii\filters\Cors 應(yīng)在 授權(quán) / 認(rèn)證 過(guò)濾器之前定義,以保證CORS頭部被發(fā)送。
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
],
], parent::behaviors());
}
Cors 可轉(zhuǎn)為使用?cors
?屬性。
cors['Origin']
: 定義允許來(lái)源的數(shù)組,可為['*']
?(任何用戶) 或?['http://www.myserver.net', 'http://www.myotherserver.com']
. 默認(rèn)為?['*']
.cors['Access-Control-Request-Method']
: 允許動(dòng)作數(shù)組如?['GET', 'OPTIONS', 'HEAD']
. 默認(rèn)為?['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
.cors['Access-Control-Request-Headers']
: 允許請(qǐng)求頭部數(shù)組,可為?['*']
?所有類型頭部 或?['X-Request-With']
?指定類型頭部. 默認(rèn)為?['*']
.cors['Access-Control-Allow-Credentials']
: 定義當(dāng)前請(qǐng)求是否使用證書(shū),可為?true
,?false
?或?null
?(不設(shè)置). 默認(rèn)為null
.cors['Access-Control-Max-Age']
: 定義請(qǐng)求的有效時(shí)間,默認(rèn)為?86400
.例如,允許來(lái)源為?http://www.myserver.net
?和方式為?GET
,?HEAD
?和?OPTIONS
?的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());
}
可以覆蓋默認(rèn)參數(shù)為每個(gè)動(dòng)作調(diào)整CORS 頭部。例如,為login
動(dòng)作增加Access-Control-Allow-Credentials
參數(shù)如下所示:
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());
}
更多建議: