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


Allow only author to edit his post in yii2 using ACF

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

它可以这样实现:

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

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

下面是我如何将ACF和RBAC结合使用。如果我错了,或者有更好的方法,请纠正我。这是基于基本模板的。

  1. 用户的角色存储在"用户"表的"角色"列中。本例中使用了另一个表"country"。假设您已经使用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博客的参考资料

# 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文件夹中

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中,覆盖以下函数以添加"访问"行为。

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