yii中间件本质是行为或过滤器,非独立类;须通过beforeaction()或accesscontrol行为实现,不可照搬laravel的authmiddleware写法。

Yii 中间件本质是行为(Behavior)或过滤器(Filter),不是独立中间件类
Yii 没有 Laravel 那种 class AuthMiddleware 形式的中间件写法。它靠控制器动作(Action)的 beforeAction()、afterAction(),或在控制器中声明 public $behaviors = [] 来实现类似能力。
常见错误现象:照着 Laravel 写一个 AuthMiddleware.php 放进 components/,然后试图在配置里注册——Yii 2.x 根本不识别这种写法,会静默忽略。
正确路径只有两条:
- 在控制器里重写
beforeAction(),手动校验登录态、权限、IP 等,最后return parent::beforeAction($action); - 用 Yii 的
AccessControl行为(最常用):public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'rules' => [ [ 'allow' => true, 'roles' => ['@'], // 登录用户 ], ], ], ]; }
Laravel 中间件可独立定义、全局/分组/路由级注册
Laravel 的 php artisan make:middleware CheckAge 会生成标准 PHP 类,含 handle() 方法,参数是 $request 和 $next。它天然支持链式调用,且注册灵活。
使用场景差异明显:
- 全局中间件(
app/Http/Kernel.php的$middleware)→ 所有请求都过一遍 - 分组中间件(
Route::middleware(['auth'])->group(...))→ 只对某组路由生效 - 单路由中间件(
Route::get('/profile', ...)->middleware('auth'))→ 最细粒度控制
性能影响上,Laravel 中间件是“请求生命周期必经环节”,每多一层,就多一次函数调用和对象实例化;Yii 的 AccessControl 是行为,在控制器初始化时一次性绑定,开销略低,但灵活性不如 Laravel。
Yii 请求过滤必须手动做,$request->get() 不等于安全
很多人误以为 $request->get('id') 是“过滤后”的值,其实它等价于 $_GET['id'],原样返回字符串,包括 "1' OR '1'='1" 这种注入片段。
真正安全的做法不是靠请求方法,而是组合验证:
- 轻量场景:用
filter_var($request->get('email'), FILTER_VALIDATE_EMAIL),但要额外判断是否为null或空字符串 - 标准做法:绑定到模型并走
validate(),比如SearchForm类定义rules(),再调用$form->load($request->get(), '') - 别忽略
Content-Type:前端发application/json,$request->post()一定为空,得用Json::decode($request->getRawBody())
Laravel 的 validate() 是请求生命周期一环,Yii 的验证是手动触发
Laravel 的控制器方法可直接声明验证规则:
public function store(Request $request)
{
$validated = $request->validate([
'email' => 'required|email|unique:users',
'age' => 'required|integer|min:18',
]);
}这个 validate() 在请求进入控制器方法前就执行了(靠中间件 ValidatePostSize 和自动注入机制),失败直接返回 422 响应。
Yii 没有这层自动拦截。你必须显式写:
$model = new User();
$model->load($request->post(), '');
if (!$model->validate()) {
return $this->asJson(['error' => $model->getErrors()]);
}漏掉 if 判断,脏数据就直接进 DB。
容易被忽略的一点:Yii 的 load() 默认只从 $_POST 取值,如果表单用了自定义 name="User[age]" 结构,load() 能自动映射;但若前端传的是扁平 JSON,比如 {"age": 25},就得先解码再逐个赋值,不能指望 load() 自动识别。











