1. 基于 AccessControl 的访问控制,一套最基本的权限控制,能识别登录用户和非登录用户(游客),还可以根据 HTTP 请求类型控制是否有权限访问。
  2. 基于角色的权限访问控制(Role-Based Access Control),简称 RBAC。(这个后期我们再讲)

很显然我们的需求比较简单,不需要引入 RBAC 这个复杂的权限控制,所以本篇文章主要就是先讲讲 AccessControl 如何使用。

基本用法

在对应的控制器文件中修改如下代码:

  1. use yii\filters\AccessControl;
  2. use yii\web\Controller;
  3. class ColumnController extends Controller
  4. {
  5. /**
  6. * @inheritdoc
  7. */
  8. public function behaviors()
  9. {
  10. return [
  11. 'access' => [
  12. 'class' => AccessControl::className(),
  13. 'rules' => [
  14. // 默认只能 GET 方式访问
  15. ['allow' => true, 'actions' => ['index', 'view'], 'verbs' => ['GET']],
  16. // 默认只能 POST 方式访问
  17. ['allow' => true, 'actions' => [], 'verbs' => ['POST']],
  18. // 登录用户 POST 操作
  19. ['allow' => true, 'actions' => [], 'verbs' => ['POST'], 'roles' => ['@']],
  20. // 登录用户才能操作
  21. ['allow' => true, 'actions' => ['create',], 'roles' => ['@']],
  22. ]
  23. ],
  24. ];
  25. }
  26. // ....
  27. }

这里我们只用到了 AccessControl 最基本的 三个参数,下面我们分别说明一下参数的含义:

  • allow:代表是否有权限访问。这意味着你也可以定制一条不允许访问的访问规则。没有这个参数的时候此条规则被认为是不允许访问规则。
  • actions:指定规则匹配的操作,是一个 Action ID 的数组。区分大小写的。如果此选项为空或未设置,则意味着该规则适用于所有操作。
  • roles:指定此规则适用的用户角色。如果此选项为空或未设置,则意味着该规则适用于所有角色。框架自带有两个特殊的角色:

    • ?:匹配游客
    • @:匹配已经登录的用户

      高级用法

      onlyverbs 的用法
      use yii\filters\AccessControl;
      use yii\web\Controller;
      class SiteController extends Controller
      {
      /**
      * @inheritdoc
      */
      public function behaviors()
      {
      return [
      'access' => [
      'class' => AccessControl::className(),
      'only' => ['logout', 'signup'],
      'rules' => [
      ['actions' => ['signup'], 'allow' => true, 'roles' => ['?']],
      ['actions' => ['logout'], 'allow' => true, 'roles' => ['@']],
      ],
      ],
      'verbs' => [
      'class' => VerbFilter::className(),
      'actions' => ['logout' => ['post']],
      ],
      ];
      }
      }
      
  • only:这个参数的值为一个 Action ID 的数组,上面的示例表示 SiteController 只控制 logout 和 signup 两个的访问操作,其他的操作不进行访问控制。

  • verbs:用来限制操作的请求类型,最常用的就是 delete 操作了,必须是 POST 操作类型。

AccessControl rules 的其他参数

  • controllers: 一个 Controller ID 的数组,颗粒度只能控制到 Controller 级别,不细化到 Action 级别。我的理解是如果前台把 AccessControl 放在统一一个地方配置的话,这个还是有点用的。不然真不知道使用场景。具体使用看源码的注释
  • roleParams: 这个要配合 RBAC 判断一个角色是否有权限的时候使用,值为角色的参数。具体使用看源码的注释
  • ips:这个参数可以设置根据 IP 判断是否是否有权限。值为数组,可以使用通配符,例如:’192.168.*’。用的频率不高。
  • matchCallback:通过回调函数,判断是否有权限使用。使用示例:

    use yii\filters\AccessControl;
    use yii\web\Controller;
    class SiteController extends Controller
    {
    /**
       * @inheritdoc
       */
    public function behaviors()
    {
    return [
    'access' => [
    'class' => AccessControl::className(),
    'rules' => [
    [
    'allow' => true,
    'actions' => ['index'],
    'matchCallback' => function ($rule, $action) {
    // 12月28号才可以访问 /site/index 方法
    return date('m-d') === '12-28';
    }
    ],
    ],
    ]
    ];
    }
    }
    
  • denyCallback: 当不设置 allow 或者 allow 设置为 false 的时候,会出发这个回调函数,如果如需要你可以通过这个回调函数执行一些业务。使用示例:

    use yii\filters\AccessControl;
    use yii\web\Controller;
    class ColumnController extends Controller
    {
    /**
       * @inheritdoc
       */
    public function behaviors()
    {
    return [
    'access' => [
    'class' => AccessControl::className(),
    'rules' => [
    [
    'allow' => false,
    'actions' => ['index'],
    'denyCallback' => function ($rule, $action) {
    // 访问 /column/index 页面的时候,跳转到 /site/index 并提示没有权限
    Yii::$app->session->setFlash('warning', '您没有权限');
    return $this->redirect(['site/index']);
    }
    ],
    ],
    ]
    ];
    }
    }
    

    统一处理,游客不允许访问后台系统
    管理后台游客一般都是不允许访问除了登录以为的地址,我又不想一个一个控制器写行为,也不想写一个基类的控制器,然后再基类里面写行为,那么如何优雅的实现这个需求呢?现在你只需要两步就能优雅的实现:
    一、修改后台配置文件 backend/config/main.php,添加三行代码:

    return [
    // ... code
    'components' => [
    // ... code
    ],
    'as access' => [
    'class' => 'common\components\AccessControl',
    ],
    // ... code
    ];
    

    二、添加 common\components\AccessControl.php 文件:

    <?php
    namespace common\components;
    use Yii;
    use yii\web\User;
    use yii\di\Instance;
    class AccessControl extends \yii\base\ActionFilter
    {
    /**
       * @var User User for check access.
       */
    private $_user = 'user';
    /**
       * Get user
       * @return User
       */
    public function getUser()
    {
    if (!$this->_user instanceof User) {
    $this->_user = Instance::ensure($this->_user, User::className());
    }
    return $this->_user;
    }
    /**
       * Set user
       * @param User|string $user
       */
    public function setUser($user)
    {
    $this->_user = $user;
    }
    /**
       * @inheritdoc
       */
    public function beforeAction($action)
    {
    $user = $this->getUser();
    return $this->denyAccess($user);
    }
    /**
       * @param User|string $user
       * @return bool
       */
    protected function denyAccess($user)
    {
    if ($user->getIsGuest()) {
    $user->loginRequired();
    }
    return true;
    }
    /**
       * @param \yii\base\Action $action
       * @return bool
       */
    protected function isActive($action)
    {
    $uniqueId = $action->getUniqueId();
    if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) {
    return false;
    }
    $user = $this->getUser();
    if ($user->getIsGuest() && is_array($user->loginUrl) && isset($user->loginUrl[0]) && $uniqueId === trim($user->loginUrl[0], '/')) {
    return false;
    }
    return true;
    }
    }
    

    as xxx 是 Yii2 里面的高级用法,以后有机会再聊吧,你现在知道可以这样用就行了。

    总结

    这一篇文章我们主要是讲了在 Yii2 中是如何实现访问控制的,通过几个简单的实例,简述了最常用的功能,并且还简单罗列了一些不常用的参数含义。
    除此之外我们还列举了后台最常用的访问控制场景。

    参考链接

  • Yii2 Authorization Doc

  • Class yii\filters\AccessRule