1. 示例
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['login', 'error', 'register', 'offline'],
'allow' => true,
],
[
'allow' => true,
'roles' => ['@'],
]
]
]
];
}
}
2. 客户端请求后的运行流程
具体运行流程请参考 《Yii2 运行流程分析之 Application》
最终会在 yii\base\Module::runAction
中创建 controller
, action
,
然后执行 $controller->runAction
public function runAction($route, $params = [])
{
$parts = $this->createController($route);
if (is_array($parts))
{
list($controller, $actionID) = $parts;
Yii::$app->controller = $controller;
$result = $controller->runAction($actionID, $params);
...
}
...
}
runAction() 中的流程请参考 《Yii2 运行流程分析之 Controller》
在 yii\base\Controller::runAction
中
会执行 this->beforeAction()
-> this->ensureBehaviors()
将 SiteController::behaviors()
中的行为绑定到 SiteController
上。
public function ensureBehaviors()
{
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}
private function attachBehaviorInternal($name, $behavior)
{
if (!($behavior instanceof Behavior))
{
$behavior = Yii::createObject($behavior);
}
if (is_int($name))
{
$behavior->attach($this);
$this->_behaviors[] = $behavior;
}
else
{
if (isset($this->_behaviors[$name]))
{
$this->_behaviors[$name]->detach();
}
// 这个名为 access 的行为将会执行到这里
$behavior->attach($this);
$this->_behaviors[$name] = $behavior;
}
return $behavior;
}
$behaviors
实际上是 AccessControl
的对象,attach
是其基类 ActionFilter
中的函数。
# yii\base\ActionFilter::attach
public function attach($owner)
{
$this->owner = $owner;
$owner->on(Controller::EVENT_BEFORE_ACTION, [$this, 'beforeFilter']);
}
将会执行 ActionFilter::beforeFilter
public function beforeFilter($event)
{
...
$event->isValid = $this->beforeAction($event->action);
...
}
# yii\filters\AccessControl::beforeAction
public function beforeAction($action)
{
$user = $this->user;
$request = Yii::$app->getRequest();
// 这些就是在 SiteController 中定义的规则
foreach ($this->rules as $rule)
{
if ($allow = $rule->allows($action, $user, $request))
{
return true;
}
elseif ($allow === false)
{
if (isset($rule->denyCallback))
{
call_user_func($rule->denyCallback, $rule, $action);
}
elseif ($this->denyCallback !== null)
{
call_user_func($this->denyCallback, $rule, $action);
}
else
{
$this->denyAccess($user);
}
return false;
}
}
if ($this->denyCallback !== null)
{
call_user_func($this->denyCallback, null, $action);
}
else
{
$this->denyAccess($user);
}
return false;
}
3. 简述
简单的说就是会在执行 controller
中的 action
(比如SiteController::actionIndex
)之前,会先执行这些 behaviors, 如果没有通过, 则 action
不会继续执行下去。