只允许作者使用ACF在yii2中编辑他的帖子

时间:2015-03-24 17:59:35

标签: php yii2 access-control role yii2-user

我使用访问控制过滤器进行访问管理,但无法完成任务 - 例如,如何让项目经理更新项目并禁止其他人?我通过matchCallback尝试了它,但在这种情况下,所有项目经理都可以更新任何项目,因为返回了TRUE。

类似更常用的规则 - 如何允许用户使用ACF更新/删除作者的帖子?

         'access' => [
            'class' => AccessControl::className(),
            'only' => ['index', 'view', 'create', 'update', 'delete'],
            'rules' => [
                [
                    'actions' => ['update'],
                    'allow' => true,
                    'roles' => ['@'],
                    'matchCallback' => function ($rule, $action) {

                        return Yii::$app->user->identity->getProjectParticipants()
                                    ->one()->isManager(Yii::$app->user->identity->id);
                    }
                ],
            ],
        ],

3 个答案:

答案 0 :(得分:4)

它可以实现如下:

use Yii;
use yii\web\Controller;
use yii\filters\AccessControl;

class MyController extends Controller
{

...

    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['update', 'delete'],
                'rules' => [
                    [
                        'actions' => ['update', 'delete'],
                        'allow' => true,
                        'roles' => ['@'],
                        'matchCallback' => function ($rule, $action) {
                            if (Yii::$app->user->can('admin') || $this->isUserAuthor()) {
                                return true;
                            }
                            return false;
                        }
                    ],
                ],
            ],
        ];
    }

    protected function findModel($id)
    {
        if (($model = MyModel::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }

    protected function isUserAuthor()
    {   
        return $this->findModel(Yii::$app->request->get('id'))->author->id == Yii::$app->user->id;
    }

...

}

答案 1 :(得分:3)

使用自定义AccessRule解决了这个问题。人们必须填写代码来检查用户是否是项目的作者。

namespace app\filters;

class AuthorAccessRule extends \yii\filters\AccessRule
{
    public $allow = true;  // Allow access if this rule matches
    public $roles = ['@']; // Ensure user is logged in.

    public function allows($action, $user, $request)
    {
        $parentRes = parent::allows($action, $user, $request);
        // $parentRes can be `null`, `false` or `true`.
        // True means the parent rule matched and allows access.
        if ($parentRes !== true) {
            return $parentRes;
        }
        return ($this->getProjectAuthorId($request) == $user->id);
     }

     private function getProjectAuthorId($request)
     {
         // Fill in code to receive the right project.
         // assuming the project id is given à la `project/update?id=1`
         $projectId = $request->get('id');
         $project = \app\models\Project::findOne($projectId);
         return isset($project) ? $project->author_id : null;
     }
}

可以通过在行为中包含此规则来使用该规则:

'authorAccess' => [
        'class' => AccessControl::className(),
        'only' => ['update'],
        'rules' => ['actions' => ['update']],
        'ruleConfig' => ['class' => '\app\filters\AuthorAccessRule'],
],

答案 2 :(得分:1)

以下是我如何使用ACF和RBAC的组合。如果我错了或者有更好的方法,请纠正我。它基于Basic模板。

  1. 用户角色存储在“用户”表的“角色”列中。在此示例中使用另一个表“country”。假设您已使用Gii生成模型和控制器。

  2. 自定义PhpManager以使用数据库表“user”中的角色。

  3. class PhpManager extends \yii\rbac\PhpManager
    {
        public function init()
        {
            parent::init();
        }
    
        public function getAssignments($userId)
        {
            if (!Yii::$app->user->isGuest) {
                $assignment = new Assignment();
                $assignment->userId = $userId;
                # Assume the role is stored in User table "role" column
                $assignment->roleName = Yii::$app->user->identity->role;
                return [$assignment->roleName => $assignment];
            }
        }
    }
    

    3.将authManager添加到web.app和console.app控制台文件。

        'authManager' => [
            'class' => 'app\components\PhpManager',
            'defaultRoles' => ['user', 'manager', 'admin', 'master'],
        ],
    
    1. 创建自定义的AccessRule。参考speixoto's blog
    2. # Reference
      # http://programming.peixoto.cf/2015/01/14/yii2-role-based-access-control-and-context-access-rule/#$$nmvkr0&&0SUmhOPVEeSW9grIhAgzZg$$
      
      class ContextAccessRule extends AccessRule
      {
      
          public $modelClass;
          public $primaryKey;
      
          protected function matchRole($user)
          {
              if (parent::matchRole($user))
                  return true;
      
              $model = $this->findModel();
      
              foreach ($this->roles as $role) {
                  # Call the CheckAccess() function which process rules
                  if ($user->can($role, ['model' => $model])) {
                      return true;
                  }
              }
              return false;
          }
      
          protected function findModel()
          {
              if (!isset($this->modelClass))
                  throw new InvalidConfigException(Yii::t('app', 'the "modelClass" must be set for "{class}".', ['class' => __CLASS__]));
              $primaryKey = $this->getPrimaryKey();
              # Get the request params
              $queryParams = \Yii::$app->getRequest()->getQueryParams();
              # Load the model
              $model = call_user_func([$this->modelClass, 'findOne'], $queryParams[join(',', $primaryKey)]);
              if ($model !== null) {
                  return $model;
              } else {
                  throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exists.'));
              }
          }
      
          # Get the primary key of the model
          protected function getPrimaryKey()
          {
              if (!isset($this->primaryKey)) {
                  return call_user_func([$this->modelClass, 'primaryKey']);
              } else {
                  return $this->primaryKey;
              }
          }

      1. 创建一个RbacController.php以生成RBAC文件(assignments.php,items.php,rules.php)到rbac文件夹中。
      2. class RbacController extends Controller
        {
            public function actionInit()
            {
                $auth = Yii::$app->authManager;
                $auth->removeAll();
        
                ### CREATE & ADD ROLES
                $user = $auth->createRole('user');
                $node = $auth->createRole('node');
                $manager = $auth->createRole('manager');
                $admin = $auth->createRole('admin');
                $master = $auth->createRole('master');
        
                $auth->add($user);
                $auth->add($node);
                $auth->add($manager);
                $auth->add($admin);
                $auth->add($master);
        
                $auth->addChild($manager, $user);
                $auth->addChild($manager, $node);
                $auth->addChild($admin, $manager);
                $auth->addChild($master, $admin);
        
                ### ADD RULES
                $ownerRule = new \app\components\OwnerRule();
                $auth->add($ownerRule);
        
                ### CREATE PERMISSIONS ###
        
                $pUpdateOwn = $auth->createPermission('updateOwn');
                $pUpdateOwn->description = 'update own';
                $pUpdateOwn->ruleName = $ownerRule->name;
                $auth->add($pUpdateOwn);
                $auth->addChild($pUpdateOwn, $pUpdate);
        
                $pDeleteOwn = $auth->createPermission('deleteOwn');
                $pDeleteOwn->description = 'delete own';
                $pDeleteOwn->ruleName = $ownerRule->name;
                $auth->add($pDeleteOwn);
                $auth->addChild($pDeleteOwn, $pDelete);
        
                ### ASSIGN PERMISSION TO ROLES
        
                $auth->addChild($user, $pUpdateOwn);
                $auth->addChild($user, $pDeleteOwn);
                $auth->addChild($manager, $pUpdateOwn);
                $auth->addChild($manager, $pDeleteOwn);
        
            }
        }

        1. 从控制台导航到项目根目录。运行./yii rbac/init(对于mac)将3个文件生成到rbac文件夹中。

        2. 在CountryController.php中,覆盖以下函数以添加“访问”行为。

        3.     public function behaviors()
              {
                  $behaviors = parent::behaviors();
          
                  $behaviors['verbs'] = [
                      'class' => VerbFilter::className(),
                      'actions' => [
                          'delete' => ['post'],
                      ],
                  ];
          
                  ['access'] = [
                      'class' => AccessControl::className(),
          //            'only' => ['view', 'index', 'create', 'update', 'delete'],
                      'rules' => [
                          [
                              'actions' => ['view', 'index'],
                              'allow' => true,
                              'roles' => ['?', '@'],
                          ],
                          [
                              'actions' => ['create'],
                              'allow' => true,
                              // Allow users, manager and admins to create
                              'roles' => ['user'],
                          ],
                          [
                              'class' => 'app\components\ContextAccessRule',
                              'modelClass' => 'app\models\Country',
                              'actions' => ['update'],
                              'allow' => true,
                              # allow owner and manager to udpate
                              'roles' => ['updateOwn', 'manager']
                          ],
                          [
                              'class' => 'app\components\ContextAccessRule',
                              'modelClass' => 'app\models\Country',
                              'actions' => ['delete'],
                              'allow' => true,
                              # allow owner and manager to delete
                              'roles' => ['deleteOwn', 'manager'],
                          ],
                      ],
                      # if user not login, and not allowed for current action, return following exception
                      'denyCallback' => function ($rule, $action) {
                          throw new UnauthorizedHttpException('You are not authorized.');
                      },
                  ];
          
                  return $behaviors;
              }
          8.测试一下。