ci4过滤器必须在filters.php中注册别名并配置作用范围才能生效,仅创建类文件无效;需确保路径、命名空间、继承接口正确,并避免登录页被自身过滤器无限重定向。

过滤器必须在 Filters.php 中注册并绑定到路由
CI4 的过滤器不会自动生效,哪怕你写了类、放对了路径,没在 app/Config/Filters.php 里声明别名和应用规则,它就完全不运行。常见错误是只创建了类文件,却忘了改配置——结果调试半天发现 before() 根本没被调用。
你需要做三件事:
- 确保过滤器类放在
app/Filters/下,命名空间为App\Filters,类名如LoginFilter,且继承\CodeIgniter\Filters\FilterInterface - 在
Filters.php的$aliases数组中添加映射:'login' => \App\Filters\LoginFilter::class - 在
$globals或$filters中指定作用范围,例如保护后台路由:'admin/*' => ['filter' => 'login'],或全局前置:'before' => ['login'](慎用,会拦截所有请求包括登录页本身)
LoginFilter 的 before() 必须手动检查 session 并重定向
CI4 不提供开箱即用的“已登录”判断,$this->session->get('user_id') 是最常用也最可靠的依据。别依赖 $this->auth 或 Myth/Auth 的 helper 函数——它们可能尚未初始化,或在过滤器生命周期中不可用。
典型写法:
public function before(RequestInterface $request, $arguments = null)
{
if (! session()->has('user_id')) {
return redirect()->to('/login')->with('error', '请先登录');
}
}
注意点:
- 不能用
exit或die,必须返回RedirectResponse实例(redirect()返回的就是) - 不要在
before()里调用$this->db或模型——过滤器早于控制器实例化,服务未完全注入;如需查库校验 token,应改用Services::database() - 若使用 Myth/Auth,它的
Authservice 在过滤器中不可直接$this->auth调用,得通过service('authentication')获取
避免登录页自身被过滤器拦截导致无限跳转
最常踩的坑:把 'login' => ['filter' => 'login'] 写进 $globals['before'],结果访问 /login 时被重定向回 /login,浏览器报 ERR_TOO_MANY_REDIRECTS。
正确做法是显式排除登录相关路由:
- 用
$filters替代$globals,只对需要保护的路径启用,例如:'admin/*' => ['filter' => 'login'] - 或者在
before()开头加白名单判断:if (in_array($request->getUri()->getPath(), ['/login', '/auth/login'])) { return; } - 别用模糊匹配如
'*' => ['filter' => 'login'],除非你真想拦截全部请求(包括静态资源)
Session 配置不当会导致过滤器始终判定未登录
即使代码逻辑正确,session()->has('user_id') 仍返回 false,大概率是 session 驱动或配置问题。CI4.7.2 默认用 CodeIgniter\Session\Handlers\FileHandler,但若 app/Config/Session.php 中 $sessionSavePath 指向不可写目录,或 $sessionMatchIP 设为 true 而前端用了代理,session 就无法持续。
快速验证方式:
- 在登录成功后,加一行
log_message('debug', 'Session user_id: ' . session()->get('user_id'));确认值已写入 - 检查 PHP 错误日志是否有
session_start(): open(/path/to/sess_*, O_RDWR) failed - 临时将
$sessionDriver改为'array'(仅开发环境),排除存储层干扰
真正难排查的是跨子域或 HTTPS/HTTP 混合场景下 cookie 的 domain 和 secure 属性不匹配——这时过滤器看到的 session 就是空的,但没有任何报错提示。











