yii2项目实战-访问控制过滤器ACF讲解
更新于 2017年07月19日 by 白狼 被浏览了 4868 次
1 1

ACF,Access Control Filter, 访问控制过滤器的意思。

所谓的访问控制过滤器?字面上来理解就是访问授权呗,对一些具体的操作设定一些规则进行权限控制。

当然,这里的【操作】即是指控制器的action了。

前面我们添加新用户的时候,不知你可有疑问:为什么我们访问主页(site/index)就让我们登录,但是我们在未登录的时候却可以直接添加用户,访问用户列表呢?

下面就请我们今天的主角 ACF 登场,噼里啪啦的鼓掌...

从程序的角度来讲,ACF 其实就是 yii\filters\AccessControl, 它比较适合简单的场景,面对的对象便是控制器的action。

对于一些复杂的验证方式,我们后面会说到 Role Based Access Control (rbac)。

我们接着刚刚抛出的疑问继续学习。

有同学又要质疑了,创建新用户的操作,肯定要后台管理员才可以进行操作,包括列表页等一系列操作,没登录肯定不能访问啊啊啊。

不急,下面我们就看看如何通过ACF去对 user-backend/* 的系列操作进行授权限制!

打开 backend\controller\SiteController.php 我们看到这样一段代码

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => ['login', 'error'],
                    'allow' => true,
                ],
                [
                    'actions' => ['logout', 'index'],
                    'allow' => true,
                    'roles' => ['@'],
                ],
            ],
        ],
        'verbs' => [
            'class' => VerbFilter::className(),
            'actions' => [
                'logout' => ['post'],
            ],
        ],
    ];
}

我们发现AccessControl是以行为behaviors的方式附加在当前控制器。

行为是啥,我们在【配置】一文中就开始纠结行为,行为说白了,他就是一个类,通过某些操作,跟现有的类进行了一个绑定。

既然是绑定,自然就是你(行为类)可以用我的(当前类),我(当前类)也可以用你的(行为类),对吧?具体细节,还是那句老话,到了该说的时候我们自然会说,现在说太多岂不是又要跑题了呀?

言归正传,我们继续看看AccessControl是怎样发挥作用的。

不妨打开yii\filters\AccessControl.php文件,init方法中我们看到 配置项rules在使用之前,都会被创建为 yii\filters\AccessRule 的对象。

也就是说我们实际的配置应该是这样的

'rules' => [
    [
        'class' => 'yii\filters\AccessRule',
        'actions' => ['login', 'error'],
        'allow' => true,
    ],
],

通过【配置】一文,很容易就猜到 这里的actions和allow就是 AccessRule的属性了。

接着我们看到实际的请求过滤是在beforeAction中进行的!也就是说,在beforeAction中加了一层过滤的条件规则!

如此一来,整个过滤的流程你是不是感觉到清晰了好多,但是还没有完,我们还没有说具体的过滤规则,从init方法中,我们了解到具体的规则即是 yii\filters\AccessRule 类的属性了。也就是说,规则怎么写,就要看你怎么设定accessRule的属性了!属性怎么设置?打开 yii\filters\AccessRule文件,看每一个具体的注解!这里就不说了,因为注解已经写得非常详细了,说多了自然就累赘,不好不好。

那下面我们就解决问题,UserBackendController 的所有操作应该都设置为登录之后才可以操作

'access' => [
    'class' => AccessControl::className(),
    'rules' => [
        [
            // 当前rule将会针对这里设置的actions起作用,如果actions不设置,默认就是当前控制器的所有操作
            'actions' => ['index', 'view', 'create', 'update', 'delete', 'signup'],
            // 设置actions的操作是允许访问还是拒绝访问
            'allow' => true,
            // @ 当前规则针对认证过的用户; ? 所有方可均可访问
            'roles' => ['@'],
        ],
    ],
],

我们再做几个小练习

1、假设index操作只允许post请求才可以访问,如何配置?

'access' => [
    'class' => AccessControl::className(),
    'rules' => [
        [
            // 当前rule将会针对这里设置的actions起作用,如果actions不设置,默认就是当前控制器的所有操作
            'actions' => ['view', 'create', 'update', 'delete', 'signup'],
            // 设置actions的操作是允许访问还是拒绝访问
            'allow' => true,
            // @ 当前规则针对认证过的用户; ? 所有方可均可访问
            'roles' => ['@'],
        ],
        [
            'actions' => ['index'],
            'allow' => true,
            // 设置只允许操作的action
            'verbs' => ['POST'],
        ],
    ],
],

我们新增加的一条规则,设置了AccessRule::verbs属性即可。

注意哦,ACF 自上向下逐一检查规则,直到匹配到一个规则。也就是说如果你这里把verbs的actions index也添加一份到上面的那一条规则,verbs这条规则就相当于废掉了!

2、假设 update 操作只有用户 test1 可以访问,其他用户不可以访问,又该如何配置?

我们现在只有一个用户 test1, 为了实现命题,你可以再去添加一个新用户 test2

'access' => [
    'class' => AccessControl::className(),
    'rules' => [
        [
            // 当前rule将会针对这里设置的actions起作用,如果actions不设置,默认就是当前控制器的所有操作
            'actions' => ['index', 'view', 'create', 'delete', 'signup'],
            // 设置actions的操作是允许访问还是拒绝访问
            'allow' => true,
            // @ 当前规则针对认证过的用户; ? 所有用户均可访问
            'roles' => ['@'],
        ],
        [
            'actions' => ['update'],
            // 自定义一个规则,返回true表示满足该规则,可以访问,false表示不满足规则,也就不可以访问actions里面的操作啦
            'matchCallback' => function ($rule, $action) {
                return Yii::$app->user->id == 1 ? true : false;
            },
            'allow' => true,
        ],
    ],
],

然后你可以通过 test1 和 test2 两个账号测试,会发现只有 test1 才可以访问 update 方法,test2 就不允许对其进行访问了。

注:用户 test1 的 userId 等于1,用户 test2 的 userId 等于2。

最后,我们不仅学会了ACF,也对user-backend/* 操作进行了部署。

思考一个问题,如果说我们的管理平台有100个controller, 每个controller有10个action, 如何处理这个授权的问题?如果又要限制某些用户(注意哦,某些可以指用户组)对某些操作有权限访问,另外一些不允许访问又该如何操作?

有人不怕麻烦:那我就加100个AccessControl, 然后第二个问题就写matchCallback, 这种答案简直就是在作死!

下一章,我们来简单了解下一种相对更强大的权限控制体系,基于角色的访问控制(rbac),敬请期待吧。