【问题标题】:Allow only author to edit his post in yii2 using ACF只允许作者使用 ACF 在 yii2 中编辑他的帖子
【发布时间】:2015-05-28 04:24:16
【问题描述】:

我正在使用访问控制过滤器进行访问管理,但无法完成一件事 - 例如,我怎样才能只允许项目经理更新项目并禁止其他人使用?我通过 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);
                    }
                ],
            ],
        ],

【问题讨论】:

  • 您找到解决方案了吗?

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


【解决方案1】:

以下是我结合 ACF 和 RBAC 的方法。如果我错了或有更好的方法,请纠正我。它基于基本模板。

  1. 用户的角色存储在“用户”表的“角色”列中。本例中使用了另一个表“国家”。假设你已经使用 Gii 生成了模型和控制器。

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

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. 创建自定义访问规则。参考来自speixoto's blog

# 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 文件夹中生成 RBAC 文件(assignments.php、items.php、rules.php)。

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 (for mac) 将 3 个文件生成到 rbac 文件夹中。

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

    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. 测试一下。

【讨论】:

    【解决方案2】:

    最好用自定义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'],
    ],
    

    【讨论】:

      【解决方案3】:

      可以这样实现:

      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;
          }
      
      ...
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-25
        • 2023-01-19
        • 1970-01-01
        • 1970-01-01
        • 2013-04-06
        • 1970-01-01
        • 1970-01-01
        • 2021-06-11
        相关资源
        最近更新 更多