简介
存取控制过滤器(ACF)是一种通过yii\filters\AccessControl类来实现的简单授权方法, 非常适用于仅需要简单的存取控制的应用。当一个用户请求一个action时,ACF会检查yii\filters\AccessControl::rules列表,判断该用户是否允许执行所请求的action。
AccessControl的例子
假设我们有这样一个控制器,
<?php
namespace app\controllers;
class BookController extends \yii\web\Controller
{
public function actionIndex()
{
return $this->render('index');
}
public function actionView()
{
return $this->render('view');
}
public function actionUpdate()
{
return $this->render('update');
}
public function actionDelete()
{
return $this->render('delete');
}
}
其中有actionIndex
、actionView
、actionUpdate
、actionDelete
四个action。
首先我们希望任何用户都能访问index、view,登录的用户可以访问update、delete,那么我们可以这样重写behaviors()函数
<?php
namespace app\controllers;
use yii\filters\AccessControl;
class BookController extends \yii\web\Controller
{
public function behaviors()
{
return [
'access'=>[
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['index','view'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['update','delete'],
'allow' => true,
'roles' => ['@'],
]
],
],
];
}
public function actionIndex()
...
public function actionView()
...
public function actionUpdate()
...
public function actionDelete()
...
}
在函数behaviors()中,
[
'class' => AccessControl::className(),
'rules' => [...],
]
创建了类yii\filters\AccessControl
的一个实例,yii\filters\AccessControl继承自yii\base\ActionFilter
,通过查阅这两个源码,除了可以配置属性rules
,还可以配置的有only
、except
、denyCallback
(user
?)。
only
维护了一个actionID数组,指明该AccessControl应当只对其中所列出的actionID方法起作用;如何没有指定该属性,则表示该AccessControl能对所有的actionID起作用。
except
维护了一个actionID数组,指明该AccessControl不应该管理的actionID。
如果一个actionID同时出现在only和except中,这个actionID不受本ActionFilter约束
denyCallback
当任意一个用户访问自己没有权限访问的actionID时,Yii会作出拒绝,这里可以自定义这个拒绝的动作。
缺省情况下:
- 如果该用户是访客,将调用yii\web\User::loginRequired()将用户的浏览器重定向到登录页面。
- 如果该用户是已认证用户,将抛出一个yii\web\ForbiddenHttpException异常。
在此基础上,我们给出一个稍微复杂的例子,
public function behaviors()
{
return [
'access'=>[
'class' => AccessControl::className(),
'only' => ['index','view','update','delete'],
'except' => ['update'],
'denyCallback' => function($rule, $action){
throw new ForbiddenHttpException("你没有权限访问这个网页");
},
'rules' => [
[
'actions' => ['index','view'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['update','delete'],
'allow' => true,
'roles' => ['@'],
]
],
],
];
}
在这个例子中,我们实例化了一个AccessControl类,only
指明该对象负责管理index、view、update和delete,except
指明该对象忽略update,only
与except
两者相结合说明该对象负责管理index、view和delete,不负责管理update。我们可以自己验证一下,update这个actionID不需要登录就可以访问,index和view不需要登录就可以访问,delete需要登录才可以访问。denyCallback
又表明,当我们使用游客身份访问delete时,将会返回一个403错误,并提示我们的自定义消息“你没有权限访问这个网页”。
AccessRule的例子
再次回到上面提到的简单的例子,
public function behaviors()
{
return [
'access'=>[
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['index','view'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['update','delete'],
'allow' => true,
'roles' => ['@'],
]
],
],
];
}
注意到rules是一个数组,通过分析源码,本质上是如下所示的,rules是一个实例化的AccessRule数组。
'rules' => [
[
//'class' => 'yii\filters\AccessRule',
'actions' => ['index','view'],
'allow' => true,
'roles' => ['?'],
],
[
//'class' => 'yii\filters\AccessRule',
'actions' => ['update','delete'],
'allow' => true,
'roles' => ['@'],
]
],
yii\filters\AccessRule中可以配置的属性除了action、allow、roles,还有controllers、ips、verbs、matchCallback、denyCallback。
action
维护了一个actionID数组,并且是大小写敏感的。如果没有设置或者设置为空,则表示该规则会应用到所有的actionID上。
allow
- true:允许访问
- false:禁止访问
roles
维护了一个角色数组,其中?
代表游客,@
代表登录的人,此外还可以是RBAC中定义的角色。
controllers
指定该规则用于匹配哪些控制器。 它的值应为控制器ID数组。匹配比较是大小写敏感的。如果该选项为空,或者不使用该选项, 则意味着当前规则适用于所有的操作。(译者注:这个选项一般是在控制器的自定义父类中使用才有意义)
ips
维护了一个IP地址数组,例如
'ips'=>[
192,168.*, //*是通配符
10.12.1.182,
],
verbs
指定该规则用于匹配哪种请求方法(例如GET,POST)。 这里的匹配大小写不敏感。
matchCallback
指定一个PHP回调函数用于 判定该规则是否满足条件。(译者注:此处的回调函数是匿名函数)
denyCallback
指定一个PHP回调函数, 当这个规则不满足条件时该函数会被调用。(译者注:此处的回调函数是匿名函数)
一个稍微负责的例子,
public function behaviors()
{
return [
'access'=>[
'class' => AccessControl::className(),
'rules' => [
//任何人都可以访问index页面
[
'actions' => ['index'],
'allow' => true,
'roles' => ['?'],
],
//指定的IP内的游客们可以访问view页面
[
'actions' => ['view'],
'allow' => true,
'ips' => [
'192.168.*',
'10.13.1.182'
],
'roles' => ['?'],
],
//登录的用户可以通过POST方式访问update页面
[
'actions' => ['update'],
'allow' => true,
'verbs' => ['POST'],
'roles' => ['@'],
],
//光棍节可以访问dog页面
[
'actions' => ['dog'],
'allow' => true,
'matchCallback' => function ($rule, $action) {
return date('d-m') === '11-11';
},
],
//愚人节这一天不可以访问fool页面
[
'actions' => ['fool'],
'allow' => true,
'matchCallback' => function ($rule, $action) {
return date('d-m') === '04-01';
},
]
],
],
];
}