Closed gimox closed 10 years ago
What are your questions that should be clarified?
// assign roles to users $auth->assign($reader, 'reader A');
What does it means? Who is 'reader A'? this is a step to do after login to assign a user to role?
GUEST rules need to be configured as defaultroles as previous version?
reader A, from what I can tell from my own implementation relates to rules and roles, otherwise known as an authorization (American spelling :) item.
I notice you talk about default assignment, you can make the role
field in the user table set user
for example to give people a default role (or in new rbac rule as everything is known).
Be-aware that if does state in the docs somewhere that if you want something more complex, like a default set of rules and roles etc etc applied then you need more complex rbac, like the DB edition.
It means a role $reader
will be assigned to a user with ID='reader A'
(usually it's integer) so when checking auth this user will be granted all permissions $reader
role has.
This is a one time step performed at user signup or change of his role.
Yes, guest role is default one.
Whoops my bad I am using pre-beta and in beta assign has switched params
so i don't understand...
i need to assign the role after login. how it work?
You don't need to assign role after login. It should be already assigned by that time.
ok. so a better focus to problem... i create the rbac.php file, autogenerateb from my console app. now if i create a new user i add a role to it from delcared role in rbac. when i login it read role field and auto assign role .
So what do this code, i don't need it ? $auth->assign($reader, 'reader A');
more more focus. i add $auth->assign($admin, 1)
to console app program so it generate file adding id 1 and roleName. Now i it read the corrected right but the problem is HOW CAN I ADD Dynamically the role assignmet like old RBAC? How set a role to a user when it log?
In order to do it based on a field in user table you need to:
Rule
class that compares role
field with role item data.role
field doesn't match.mm rbac from beta version is the bad think of this framework.. switch to my custom rbac... waiting for a more robust rbac.
There won't be any design changes about it.
i think assign function need to be changed, it accept $role as object. to assign on the fly, i create a assign function that accept $role as string and i can do lke this: assignNow('admin','1'); i think this is the problem
@qiangxue thoughts?
@gimox Have you ever read the last part of the doc? https://github.com/yiisoft/yii2/blob/master/docs/guide/authorization.md#using-default-roles
You should not assign a role to a user on the fly and rely on the fact that the assignment is not saved. This is a bad design in 1.1 and is fixed in 2.0 now.
For your case, you should just use the default roles as explained in the doc. There's no assignment needed since you are using default roles.
A very bad design for me, not dynamic and not so usefull as precendent alpha. This is my opinion.
@gimox I hope you take time to really understand the new design instead of judging the design because you have to make changes to your current code.
In the old design, when you use PhpManager and DbManager you would get different results: using PhpManager if you call assign()
, the assignment is actually not saved until you explicitly call save()
; while using DbManager, calling assign()
will save the assignment immediately. This is the inconsistency fixed by the new design. The way you use assign()
with PhpManager is indeed a hack rather than an expected usage.
Anyway, I have pointed to you what to read to solve your problem. In a word, there's no need to call assign()
like you did anymore. I consider this as a better and more consistent design than before.
I take some time to understand it, but what is not good form is the default admin management.
@qiangxue i implemented the default roles... they are no so bad (the best goals is it that i can switch to phpmanager/dbmanager in a seconds), but i have a question. i try with 2 default roles: admin and operator
i add to admin the operators auto adding $auth->addChild($$admin, $operators);
so i define the default 2 roles in my main config. It work but in controller i have this filter:
'roles' => ['operators'],
befaur using default roles it work with admin because admin has operators inside.
But now Admin has all child of operators but is not recognized as operators role and access is negated. the problem is that withoud default role it work and with default role this not work, cm be a bug?
But now Admin has all child of operators but is not recognized as operators role and access is negated.
the reverse does not work, an admin is only operator when the role is a child, not when the set of operator permissions are the same as for admin. also you should only check against permissions in your code, not against the role.
@cebe ok so hyou mean that now with beta rbac i can not use in access filter the reverse? so now if i add operators to admin it add only child but is recognized allways as Admin and not as Admin and opertors?
(so it's logical but a drastic difference between alpha) it's correct?
I'm afraid I do not understand what you are doing. Maybe show some code.
so i use in controller a filter access control with roles 'roles' => ['operators'],
before now i assume that if admin has operators child it can be recognized as Admin and as operators.
now if admin has operators as child it has only the child but is not recognized as operators. So if admin open the controller with this accessControl 'roles' => ['operators'], it return false.
this is the correct design for beta rbac?
if this is correct i think that correct way to use accessFilter is check not the role but the rules
is correct?
@gimox, I think your operators
role has an associated rule, isn't it ?
@qiangxue I wonder if this behavior is expected or is a bug, but consider the following scenario:
User Model has a role
field. Can be users
, operators
, or admins
Rbac hierarchy as follow:
$userRole=new UserRoleRule(); // this rule will check the role field in user model
/* ... */
return [
'rules' => [
$userRole->name => serialize ($userRole),
],
['items'] => [
/** Permission Items **/
['doSomething0] => [
'type' => Item::TYPE_PERMISSION,
'description' => 'Manage Thing 0',
'ruleName' => null,
'data' => null,
],
['doSomething1'] => [
/* Other permission item */
],
/* Roles */
['users'] => [
'type' => Item::TYPE_ROLE,
'description' => 'Authenticated Users',
'ruleName' => $userRole->name,
'data' => null,
'children' => [ 'doSomething0'],
],
['operators'] => [
'type' => Item::TYPE_ROLE,
'description' => 'Operators ',
'ruleName' => $userRole->name,
'data' => null,
'children' => [ 'users', 'doSomething1'], // Operators should also have users permissions, but they can also doSomething1
],
['admins'] => [
'type' => Item::TYPE_ROLE,
'description' => 'Administrators',
'ruleName' => $userRole->name,
'data' => null,
'children' => ['operators', 'users'],
],
];
users
, operators
and admins
roles are added to defaultRoles
, therefore, users are automaticalled assigned to correct roles when login.
When you check for a permission (doSomething1
for example) with $user->can()
, or, more generally, for a item WITHOUT a rule, it will work because the checkAccessRecursive
method will check every child. BUT, when a child item has a rule that does not match (i.e, operators
role which is a child of admins
won't match because the role
property is not operators
for an admin user), then, checkAccessRecursive
will return false
.
Is it the expected behavior ?
I've updated docs. Please check if it's better now.
@tof06 Yes, this is expected. It is so because your UserRoleRule
is "flat", not aware of the hierarchical relationships between these roles.
@tof06 it has an associated rule. i follow the doc guide fopr default role. it bind the main role, my role has a children with an other role and this is not assigned.
@gimox What is your rule?
namespace frontend\rbac;
use yii\rbac\Rule;
class UserGroupRule extends Rule
{
public $name = 'userGroup';
public function execute($user, $item, $params)
{
$role = \Yii::$app->user->identity->role;
return $role == 'agencyManager' && $item->name === 'agencyManager' || $role == 'operators' && $item->name === 'operators';
}
}
config
'authManager' => [
'class' => 'yii\rbac\PhpManager',
// 'class' => 'yii\rbac\DbManager',
'defaultRoles' => [
'operators',
'agencyManager',
],
i create auth using console script
@tof06 Yes, this is expected. It is so because your UserRoleRule is "flat", not aware of the hierarchical relationships between these roles.
@qiangxue Do you mean that the rule should assign every "child" role in the hierarchy ?
In my opinion, if a user is assigned to a role, it should be also assigned to every child roles and permissions.
But maybe I'm not using rules
and defaultRole
correctly ? :)
ps my problem append with phpManager and Dbmanager
@tof06 When checkAccess()
, it will start from the permission/role you are checking with, going to the top along the RBAC hierarchy until it hits an assignment to the user. During this course, it will check rules associated with the permissions/roles along the path. If any rule returns false, the access check will return false. If there are multiple paths, it will try to find one valid path.
? i can not get the solution from your words..
@qiangxue Yes, I fully understand the process (and I've rewritten part of it! ;) ), but what I mean, is that we cannot use RBAC hierarchy with default roles, unless the associated rule check for children.
@gimox A solution would be to separate roles. Ex:
'userRole' => ['type' => Item::Role, 'name' => 'userRole', 'children' => ['Perm1', 'Perm2'], /****/],
'operatorRole' => ['type' => Item::Role,'name' => 'operatorRole', 'children' => ['userRole, 'perm3', 'perm4'],
'adminRole' => ['type' => Item::Role,'name' => 'adminRole', 'children' => ['operatorRole', 'perm5', 'perm6'],
'users' => ['type' => Item::Role,'name' => 'users', 'rule' => $userRule->name, 'children' => 'userRole'],
'operators' => ['type' => Item::Role,'name' => 'operators', 'rule' => $userRule->name, 'children' => 'operatorRole'],
'admins' => ['type' => Item::Role,'name' => 'admins', 'rule' => $userRule->name, 'children' => 'adminRole'],
and put users
,operators
and admin
in defaultRoles
Then, in your AccessRule
, use the XXXRole
instead of XXX
. This way, when an admin is checked for permission, it will check in adminRole
and its children, and because the children don'tt have rules, it should work.
Another solution (maybe more elegant) is to change the rules to check the RBAC hierarchy before returning false
@tof06 Yes, the rules for default roles have to respect hierarchy of the default roles as well. I don't see we can work around this because this is how RBAC is supposed to work.
@qiangxue I was just updating my previous comment. Thanks for your explanations and your time.
and:
this because this is how RBAC is supposed to work.
is everything we need to know. :)
Just added some doc about this: https://github.com/yiisoft/yii2/commit/e04dca4daea7c2ba86396332d6e426454dfbfe03
OK. I have followed latest doc and generated rbac , but since I am using default roles, the current user is not assigned already in rbac.php,
then I have got the below error
exception 'yii\base\ErrorException' with message 'Illegal offset type in isset or empty' in /usr/local/var/www/matchlink/vendor/yiisoft/yii2/rbac/PhpManager.php
Below is the line of code causing above error
return isset($this->_assignments[$userId]) ? $this->_assignments[$userId] : [];
then I have added sample assignments to rbac.php and dumped $this->_assignments
Below is the vardump but the error is same
[vardump-] [ 24 => [ 'user' => yii\rbac\Assignment#1 ( [userId] => 24 [roleName] => 'user' [createdAt] => null ) ] 25 => [ 'admin' => yii\rbac\Assignment#2 ( [userId] => 25 [roleName] => 'admin' [createdAt] => null ) ] ]
Below is my rbac.php
array ( 'user' => array ( 'type' => 1, 'ruleName' => 'userGroup', 'assignments' => array ( 24 => array ( 'roleName' => 'user', ), ), ), 'admin' => array ( 'type' => 1, 'ruleName' => 'userGroup', 'children' => array ( 0 => 'user', ), 'assignments' => array ( 25 => array ( 'roleName' => 'admin', ), ), ), ), 'rules' => array ( 'userGroup' => 'O:25:"common\\rbac\\UserGroupRule":3:{s:4:"name";s:9:"userGroup";s:9:"createdAt";N;s:9:"updatedAt";N;}', ), ];
If I comment the line 87 which is causing error in phpManager and return empty array from
public function getAssignments($userId), the default roles are working as expected. Please ... help... thanks in advance
What's the complete error call stack? How do you call checkAccess()
?
@qiangxue Below is the stack trace, I am using mongodb
2014-04-21 08:23:23 [127.0.0.1][5339970b21182fb7020041a7][92aa23kjpk1dmqsjps3sufsol3][error][yii\base\ErrorException:2] exception 'yii\base\ErrorException' with message 'Illegal offset type in isset or empty' in /usr/local/var/www/advanced/vendor/yiisoft/yii2/rbac/PhpManager.php:88 Stack trace: #0 /usr/local/var/www/advanced/vendor/yiisoft/yii2/rbac/PhpManager.php(88): yii\base\ErrorHandler->handleError(2, 'Illegal offset ...', '/usr/local/var/...', 88, Array) #1 /usr/local/var/www/advanced/vendor/yiisoft/yii2/rbac/PhpManager.php(78): yii\rbac\PhpManager->getAssignments(Object(MongoId)) #2 /usr/local/var/www/advanced/vendor/yiisoft/yii2/web/User.php(596): yii\rbac\PhpManager->checkAccess(Object(MongoId), 'user', Array) #3 /usr/local/var/www/advanced/vendor/yiisoft/yii2/filters/AccessRule.php(151): yii\web\User->can('user') #4 /usr/local/var/www/advanced/vendor/yiisoft/yii2/filters/AccessRule.php(103): yii\filters\AccessRule->matchRole(Object(yii\web\User)) #5 /usr/local/var/www/advanced/vendor/yiisoft/yii2/filters/AccessControl.php(111): yii\filters\AccessRule->allows(Object(yii\base\InlineAction), Object(yii\web\User), Object(yii\web\Request)) #6 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/ActionFilter.php(71): yii\filters\AccessControl->beforeAction(Object(yii\base\InlineAction)) #7 [internal function]: yii\base\ActionFilter->beforeFilter(Object(yii\base\ActionEvent)) #8 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/Component.php(546): call_user_func(Array, Object(yii\base\ActionEvent)) #9 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/Controller.php(254): yii\base\Component->trigger('beforeAction', Object(yii\base\ActionEvent)) #10 /usr/local/var/www/advanced/vendor/yiisoft/yii2/web/Controller.php(107): yii\base\Controller->beforeAction(Object(yii\base\InlineAction)) #11 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/Controller.php(146): yii\web\Controller->beforeAction(Object(yii\base\InlineAction)) #12 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/Module.php(423): yii\base\Controller->runAction('', Array) #13 /usr/local/var/www/advanced/vendor/yiisoft/yii2/web/Application.php(82): yii\base\Module->runAction('albms/albums', Array) #14 /usr/local/var/www/advanced/vendor/yiisoft/yii2/base/Application.php(354): yii\web\Application->handleRequest(Object(yii\web\Request)) #15 /usr/local/var/www/advanced/frontend/web/index.php(17): yii\base\Application->run() #16 {main} 2014-04-21 08:23:23 [127.0.0.1][5339970b21182fb7020041a7][92aa23kjpk1dmqsjps3sufsol3][info][application] $_GET = array ( 'r' => 'albms/albums', 'profile_id' => '53399a3f21182fb7020041a8', 'type' => 'agent', ) $_COOKIE = array ( 'PHPSESSID' => '92aa23kjpk1dmqsjps3sufsol3', '_csrf' => '2761b28bd5527e87113164b5fde23873b425904a1d05d42496f2a20d5024fcdes:32:"bWaq4OtLR56ZPZ6M2K3lkMF-MtRkmtvZ";', '_identity' => 'aca3db52cc1e46ba1cce26a41e9631d974bab81077220d5b407281e3c78e548fs:79:"[{"$id":"5339970b21182fb7020041a7"},"hrUjB0NXThz7EJbChAb_fVeqRFFBkpsb",2592000]";', ) $_SESSION = array ( '__flash' => array ( ), 'yii\\authclient\\clients\\GoogleOAuth_32a49e14871273640c5634fbe4e35b687ef3b98f_token' => yii\authclient\OAuthToken::__set_state(array( 'tokenParamKey' => 'access_token', 'tokenSecretParamKey' => 'oauth_token_secret', '_expireDurationParamKey' => 'expires_in', '_params' => array ( 'access_token' => 'ya29.1.AADtN_Xa-6b7Me6hpChRA4HUj7hAPrYH9FR3pFFvP4ng2x196s3jmT2ZQG3mku0LQPRvWQ', 'token_type' => 'Bearer', 'expires_in' => 3600, 'id_token' => 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjFiOGZlMDE5NmUxMWY2ODk0ZjI4ZmI2MzQwNDVkN2Q1MjRhMWM4N2IifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiaWQiOiIxMDY3NDYyNTI0NTAwMzE0MzAyMjQiLCJzdWIiOiIxMDY3NDYyNTI0NTAwMzE0MzAyMjQiLCJhenAiOiIzNDI3OTQzNDYxOTMtY3RwZXZvNzQxdTA0dnBiN2IyZ3VvNTBsYTU3bDkxbmMuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6Imt1bWFyMjhtQGdtYWlsLmNvbSIsImF0X2hhc2giOiJLdEY0T1FvS05oSk4tMmFTMTVER1pBIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF1ZCI6IjM0Mjc5NDM0NjE5My1jdHBldm83NDF1MDR2cGI3YjJndW81MGxhNTdsOTFuYy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInRva2VuX2hhc2giOiJLdEY0T1FvS05oSk4tMmFTMTVER1pBIiwidmVyaWZpZWRfZW1haWwiOnRydWUsImNpZCI6IjM0Mjc5NDM0NjE5My1jdHBldm83NDF1MDR2cGI3YjJndW81MGxhNTdsOTFuYy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImlhdCI6MTM5ODAyNzYwNiwiZXhwIjoxMzk4MDMxNTA2fQ.koQ22OhOGqzUNsj4dpa2eNnAdhJ_7jK-ADSYJReBRzO_df5hwTOK6uLDxt2TDcv8jvPu5ss0gem80Sr3sGJAs9_nob00TGuoYsDvtR_s9dUwOKQT7n7mbkGp5BWztY67wvYESOhhw0HaebFBfiOME103__kCB7yrDkg9v2Q7eV8', 'refresh_token' => '1/SZ_AurLpXtY7FrIol0WcSxb5d3sCDRS1lIZcxuWM7x8', ), 'createTimestamp' => 1398027906, )), '__id' => MongoId::__set_state(array( '$id' => '5339970b21182fb7020041a7', )), 'profileId' => '53399a3f21182fb7020041a8', 'userType' => 'agent', )
@qiangxue Thanks for your kind help
This got fixed by returning string
from the below method in User model
public function getId() { return (string)$this->getPrimaryKey(); }
It wasted lot of time for me. However lot happier now as I am back in track now with recent version
One issue in advanced application, how to use rules with both applications, frontend and backend, noting that the backend should generate these rules, both the backend as frontend, would create rules and invocalas according to each application?
Specify component in common config.
The rules would be defined by the rbac file in the common folder would it not, just included into the config as samdark hinted.
The doubt is as follows, 2 controllers / frontend / controllers / BlogController.php and / frontned / modules / blog / controllers / BlogController.php
When creating the rule for the actions of the blog, blog / * system does not separate by application, the User will have access to the general rule.
Of course you should have separate rules for separate actions you can do with your content.
I know I could create a condition and compare if it is an administrator, etc. would be more interesting if it were possible to create the rules and assign the desired application?
What do you mean?
Check the docs, it already covers it in the example.
example
we have 3 applications
app1 / app2 / app3 /
And several controllers with different actions, it would be interesting to create the rules and assign per application or more than one,
We assign rules to users, we could also assign applications and fazelas communicate globally without the need to create an action for each application as simple actions, I create unnecessary rules for 3 applications and not be able to set per application, besides the fact that is not dynamic
RBAC doc seem to be criptic, can anyone add doc more usefull for set a phpmanager RBAC? (like old one)