CodeIgniter4 控制器過濾器

2020-08-17 15:13 更新

控制器過濾器可以是在控制器運(yùn)行前或者運(yùn)行后執(zhí)行相應(yīng)的操作,與 事件 不同,你可以非常簡單、方便的選擇在應(yīng)用程序的哪個(gè) URI 上應(yīng)用過濾器。 過濾器可以修改傳入的請(qǐng)求,也可以對(duì)響應(yīng)做出修改,從而具有很大的靈活性和功能性。我們可以使用過濾器執(zhí)行一些共同的常見的任務(wù),例如:

  • 對(duì)于傳入的請(qǐng)求執(zhí)行 CSRF 驗(yàn)證
  • 根據(jù)用戶角色控制顯示的功能
  • 在某些功能或接口執(zhí)行請(qǐng)求速率限制
  • 顯示 “停機(jī)維護(hù)” 頁面
  • 自動(dòng)執(zhí)行內(nèi)容協(xié)商操作(例如設(shè)置 Accept-Language 值)
  • 更多

創(chuàng)建過濾器

過濾器類必須實(shí)現(xiàn) CodeIgniter\Filters\FilterInterface 接口。 過濾器類必須有 2 個(gè)方法:before()after(),它們會(huì)在控制器運(yùn)行之前和之后執(zhí)行。 如果你的業(yè)務(wù)只需要其中一個(gè)方法,那另外的方法留空即可,不可以刪除。 一個(gè)標(biāo)準(zhǔn)的過濾器類模板如下:

  1. <?php namespace App\Filters;
  2. use CodeIgniter\HTTP\RequestInterface;
  3. use CodeIgniter\HTTP\ResponseInterface;
  4. use CodeIgniter\Filters\FilterInterface;
  5. class MyFilter implements FilterInterface
  6. {
  7. public function before(RequestInterface $request)
  8. {
  9. // Do something here
  10. }
  11. //--------------------------------------------------------------------
  12. public function after(RequestInterface $request, ResponseInterface $response)
  13. {
  14. // Do something here
  15. }
  16. }

前置過濾器

任何過濾器,你都可以返回 $request 對(duì)象并且可以對(duì)當(dāng)前的請(qǐng)求進(jìn)行更改替換,這些更改在后續(xù)的控制器執(zhí)行時(shí),仍然有效。

因?yàn)槭乔爸眠^濾器,它會(huì)在控制器被執(zhí)行前觸發(fā),所以你有時(shí)會(huì)希望做一些驗(yàn)證操作,不執(zhí)行后續(xù)的控制器,例如登錄驗(yàn)證。那么你可以通過返回不是請(qǐng)求對(duì)象的任何形式來做到這一點(diǎn)。 通常是執(zhí)行重定向。 例如以下的示例:

  1. public function before(RequestInterface $request)
  2. {
  3. $auth = service('auth');
  4. if (! $auth->isLoggedIn())
  5. {
  6. return redirect('login');
  7. }
  8. }

如果返回了 Response 對(duì)象,那么 Response 對(duì)象會(huì)發(fā)送到客戶端,并且程序會(huì)停止運(yùn)行。這對(duì)實(shí)現(xiàn) API 速率限制很有作用,詳細(xì)可以參考 app/Filters/Throttle.php 相關(guān)示例。

后置過濾器

后置過濾器與前置過濾器幾乎一樣,不同的是后置過濾器只返回 $response 對(duì)象。并且,你無法停止程序的運(yùn)行。你只能對(duì) $response 對(duì)象 做一些修改,比如為了確??蛻舳丝梢哉WR(shí)別而設(shè)置某些安全選項(xiàng),或者使用緩存輸出,甚至可以使用錯(cuò)別字過濾器過濾最終的輸出內(nèi)容。

配置過濾器

創(chuàng)建完過濾器后,你需要在 app/Config/Filters.php 配置它的運(yùn)行時(shí)機(jī)。該文件包含了 4 個(gè)屬性,可以精確控制過濾器的運(yùn)行時(shí)機(jī)。

$aliases

$aliases 數(shù)組可以將一個(gè)簡單的名稱與一個(gè)或多個(gè)完整類的路徑進(jìn)行綁定關(guān)聯(lián),這些完整的類就是需要運(yùn)行的過濾器:

  1. public $aliases = [
  2. 'csrf' => \CodeIgniter\Filters\CSRF::class
  3. ];

別名是強(qiáng)制性的,如果你嘗試使用完整的類名,系統(tǒng)會(huì)觸發(fā)一個(gè)錯(cuò)誤。以別名方式定義,可以很容易的切換實(shí)現(xiàn)類。例如當(dāng)你需要替換其他過濾器時(shí),只需 要更改別名對(duì)應(yīng)的類即可。

當(dāng)然,你也可以將多個(gè)過濾器綁定到一個(gè)別名中,這樣可以使復(fù)雜的過濾器組變得簡單:

  1. public $aliases = [
  2. 'apiPrep' => [
  3. \App\Filters\Negotiate::class,
  4. \App\Filters\ApiAuth::class
  5. ]
  6. ];

你可以在 $aliases 中定義多個(gè)別名以滿足系統(tǒng)需求。

$globals

這部分允許你定義應(yīng)用程序中每個(gè)請(qǐng)求需要經(jīng)過的過濾器。 請(qǐng)一定要注意過濾器的數(shù)量,因?yàn)樗械恼?qǐng)求都將經(jīng)過這些過濾器,過多會(huì)導(dǎo)致影響性能??梢栽?beforeafter 中添加別名來指定 過濾器:

  1. public $globals = [
  2. 'before' => [
  3. 'csrf'
  4. ],
  5. 'after' => []
  6. ];

有時(shí)候你希望對(duì)絕大多數(shù)請(qǐng)求都使用過濾器處理,但個(gè)別請(qǐng)求需要單獨(dú)處理時(shí),這樣的情況很常見。 一個(gè)常見的場(chǎng)景,你需要在CSRF預(yù)防過濾器中排除一些請(qǐng)求,例如來自第三方的請(qǐng)求或者特定的 URI 地址,其他請(qǐng)求則必須經(jīng)過 CSRF 驗(yàn)證。 那么,我們可以通過 except 來實(shí)現(xiàn),可以定義一個(gè)或多個(gè)排除的 URI 地址:

  1. public $globals = [
  2. 'before' => [
  3. 'csrf' => ['except' => 'api/*']
  4. ],
  5. 'after' => []
  6. ];

可以設(shè)置任意完整的 URI,也可以使用正則表達(dá)式,或者像本示例一樣,設(shè)置 星號(hào)* 通配符的形式來設(shè)置。這樣以 api/ 開頭的所有請(qǐng)求都將不受 CSRF 過濾器的保護(hù)。但該應(yīng)用程序的其他請(qǐng)求不受影響。如果你需要指定多個(gè) URI,可以使用數(shù)組的形式即可,具體可以參考示例:

  1. public $globals = [
  2. 'before' => [
  3. 'csrf' => ['except' => ['foo/*', 'bar/*']]
  4. ],
  5. 'after' => []
  6. ];

$methods

你可以將過濾器應(yīng)用于請(qǐng)求的某些方法,例如 POST、GET、PUT等,在數(shù)組中使用全部小寫的形式指定過濾器名稱,與 $globals$filters 屬性設(shè)置目的不同,這些過濾器全部都是前置過濾器,也就是說都在控制器運(yùn)行前執(zhí)行:

  1. public $methods = [
  2. 'post' => ['foo', 'bar'],
  3. 'get' => ['baz']
  4. ]

除標(biāo)準(zhǔn)的 HTTP 方法外,還支持兩種特殊的方法:’cli’ 和 ‘a(chǎn)jax’。它們是所有的 ‘cli’ 命令行運(yùn)行的請(qǐng)求和 AJAX 請(qǐng)求。

注解

AJAX 請(qǐng)求的界定在 X-Requested-With 標(biāo)志,在某些情況下,X-Requested-With 不會(huì)通過 JavaScript 的 XHR 請(qǐng)求發(fā)送到后端,從而導(dǎo)致過濾器無法執(zhí)行。如何避免此類問題,請(qǐng)參照文檔的 [AJAX 請(qǐng)求]() 章節(jié)。

$filters

這個(gè)屬性是過濾器別名數(shù)組,每個(gè)別名可以定義指定 URI 的前置或后置過濾器:

  1. public filters = [
  2. 'foo' => ['before' => ['admin/*'], 'after' => ['users/*']],
  3. 'bar' => ['before' => ['api/*', 'admin/*']]
  4. ];

默認(rèn)提供的過濾器

CodeIgniter4 默認(rèn)綁定了三個(gè)過濾器:Honeypot、Security 和 DebugToolbar。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)