7

アクセス管理に Access Control Filter を使用していますが、1 つのことを行うことができません。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);
                    }
                ],
            ],
        ],
4

3 に答える 3

7

次のように実装できます。

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

...

}
于 2015-12-29T10:55:08.890 に答える
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'],
],
于 2015-06-25T13:06:47.600 に答える
1

Following is how I do it with combination of ACF and RBAC. Please correct me if I am wrong or there is better way of doing it. It's based on Basic template.

  1. User's role is stored in the "role" column of the "user" table. Another table "country" is used in this example. Assume you have generated models and controllers using Gii.

  2. Customise PhpManager to use role from database table "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. Add authManager to web.app and console.app console file.

    'authManager' => [
        'class' => 'app\components\PhpManager',
        'defaultRoles' => ['user', 'manager', 'admin', 'master'],
    ],
  1. Create a customized AccessRule. Reference from 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. Create a RbacController.php to generate RBAC files (assignments.php, items.php, rules.php) into rbac folder.

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. From console, navigate to your project root. Run ./yii rbac/init (for mac) to generate the 3 files into rbac folder.

  2. In CountryController.php, override following function to add "access" behaviors.

    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. Test it out.

于 2015-04-16T09:28:00.693 に答える