Reputation: 175
I have been struggling with Yii2 RBAC for a week now gathering info from all sorts of sites but I wasn't able to get it to work properly. My current situation consists of two ways: the RBAC blocks everything or the guest can access everything.
My main problem is getting RBAC to allow the users to access the pages allocated to them. The weird thing is that the Yii::$app->user->can("/" . Yii::$app->controller->id . "/" . Yii::$app->controller->action->id);
function returns true
properly for authenticated users, however if I embed it into the access control rules in the controller, it fails to work (gives 403).
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['index', 'about', 'error', 'test'],
'allow' => true,
],
[
'actions' => ['login'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
[
'allow' => Yii::$app->user->can("/" . Yii::$app->controller->id . "/" . Yii::$app->controller->action->id),
'actions' => [Yii::$app->controller->action->id],
]
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
I have found a way around this by instead of hardcoding that condition into the rules array, I am inserting a short snippet before the return
command which adds the current action as an allowed one through array_merge
if the user can indeed access that location. The authenticated users rights are now applied correctly, however, this always returns true
for the guests (they have rights to everything basically).
$rules = [];
if (!Yii::$app->user->isGuest) {
if (Yii::$app->user->can("/" . Yii::$app->controller->id . "/" . Yii::$app->controller->action->id)) {
$rules[] = [
'allow' => true,
'actions' => [Yii::$app->controller->action->id],
];
}
}
return [
'access' => [
'class' => AccessControl::className(),
'rules' => array_merge($rules, [
[
'actions' => ['index', 'about', 'error', 'test'],
'allow' => true,
],
[
'actions' => ['login'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
]),
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
I've tested the guest rights like this:
var_dump(Yii::$app->user->can("/site/dashboard"));
die;
It returns bool(true)
for any action I give it. If I'm logged in, it functions as it is intended in the auth database tables.
Any help is appreciated, either to spot the error in my solution or to point out how to use RBAC properly with guest and with behaviors. Or possibly to help me understand why would it return true when there is no authenticated user.
Thank you.
Upvotes: 0
Views: 257
Reputation: 3517
The problem in your code is that you trying to pass in User
function can()
wrong parameter. In documentation it is state that:
can() public method
Checks if the user can perform the operation as specified by the given permission.
But you trying to pass an url.
You have to assign permission in RBAC rules something like that: admin has
permission accessAdminDash
console/controllers/RbacController
$auth = Yii::$app->authManager;
$dashboard = $auth->createPermission('accessAdminDash');
$dashboard->description = 'Admin manager panel';
$auth->add($dashboard);
//It can be more permissions
$admin = $auth->createRole('admin');
$admin->description = 'Administrator';
$admin->ruleName = $rule->name;
$auth->add($admin);
//Can be more Roles
//assign Permission to a role
$auth->addChild($admin, $dashboard);
And after that you can check your permission for specific user
like this:
Yii::$app->user->can('accessAdminDash'); //here is your permission
and at the time of your controller action, you can check or create a private method which will check current user:
if(Yii::$app->user->can('accessAdminDash'))
{
//Ok this user CAN access
}
throw new ForbiddenHttpException();
or in AccessControl check role like this:
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['admin-page'],
'allow' => true,
'roles' => ['admin'], //Here is your role
]
],
],
];
}
Hope this will give you a right direction.
Upvotes: 0