我正在使用访问控制过滤器进行访问管理,但一件事无法完成——例如,我如何只允许项目经理更新项目并禁止其他人使用?我通过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结合使用。如果我错了,或者有更好的方法,请纠正我。这是基于基本模板的。
-
用户的角色存储在"用户"表的"角色"列中。本例中使用了另一个表"country"。假设您已经使用Gii生成了模型和控制器。
-
自定义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'],
],
- 创建自定义的访问规则。来自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;
}
}
- 创建一个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);
}
}
从控制台,导航到您的项目根目录。运行
./yii rbac/init
(适用于mac)将这3个文件生成到rbac文件夹中。在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.测试一下。