Yii 1.1: CPhpAuthManager - how it works, and when to use it

7 followers

Introduction

Before reading this article, you should first learn this How to setup RBAC with a php file

It is actually mentioned in the documentation

CPhpAuthManager : CPhpAuthManager is mainly suitable for authorization data that is not too big (for example, the authorization data for a personal blog system). Use CDbAuthManager for more complex authorization data.

So you maybe mistakenly thought it was perfect and would allow you to manage the roles of the next website with million users, and it doesn't ... BUT there are ways to improve it actually, if your hierarchy structure is simple, so you can serve up to million users with it.

Why CPhpAuthManager can be evil?

At the first glance what is the problem? You set auth.php file, it has the rules - no problems.

But actually when you dig deeper you understand there is a lot of issues with it .

Lets take a look at the CPhpAuthManager::assign The key to start understanding is this snippet:

$this->_assignments[$userId][$itemName]

when you assign a role to some userId, it is added to the existing assignments, userId serve as key, and that is how the access is checked... just like

isset($this->_assignments[$userId][$itemName])

Now as you saw in the code, there is no sessions there, so if you don't save next time user go to another page, no roles...

so you should save at the end of role assignment or revoke (at and of cycle, not in the middle!!!)

Now to the punch line

CPhpAuthManager::save

what it does is it takes all the assignments and roles and just write them to auth.php

THe problem: Remember?

$this->_assignments[$userId][$itemName]

So as you I think understood, auth.php will be overwritten, and rows with users ID will be added to each role...

So if you have for example 10000 users, you will have about 10000+ rows inside auth.php loaded every time !!!

if you have 100000 it will just break...

cause it overwrite it every time!!!

What to do?

So as mentioned in the documentation, if you don't use some smart strategy, you should not use CPhpAuthManager for project with more than few hundred users!

But... if your hierarchy is simple like:

banned, guest, user, moderator, admin

And in most of the websites this is the case...

You can follow this rules and handle a million users easily!

The rules

1) Never revoke if you don't delete the user or change row...
2) assign role and do CPhpAuthManager::save if and only if the user is assigned with moderator or admin rule
3) in accessControl never use

'roles'=>array('user')

Assuming that you have some role field in your users table...

the banned rule will serve you in the authorization... no reason to assigned save it at all, just don't login banned users!

instead of 'roles'=>array('user') always use the @ for guests use ? Like this:

'users' => array('@')

3) use the

'roles'=>array('someROle')

only for moderators and admins!

Conclusion

If you follow this rules, if you have 1 million of users. You will have about 100 moderators and few admins... so it is peace of cake for CPhpAuthManager if you follow the rules.

You just need to remember that for every role assignment hou have to add a row to your auth.php file that is loaded every time!

Addition1

I described the issue, but it is always better to do it yourself to understand in more depth what is the "problem" with it. And don't understand me wrong... it is awesome! but it not meant to work with a lot of users and assignments.

Just do this loop after you set the basic rules in auth.php

$auth = Yii::app()->authManager;
for($userID=1;$userID<10000;$userID++)
   $auth->assign('user', $userID);
$auth->save();

execute it and after this open the "data/auth.php".

Total 5 comments

#10242 report it
emix at 2012/10/13 11:44am
That's so wrong

You misunderstood the concept of CPhpAuthManager and you are making people believe the same and guiding them to repeat your misconception.

You really should delete this wiki.

#6622 report it
ianaré at 2012/01/22 12:18pm
Similar solution

I use a similar solution as described below, using the auth file definition only for roles. When a user logs in, their role is loaded to session and assigned in the authmanager init.

The other advantage of this technique, is that allows dynamic authorizations. In my usage case, a user can have different roles for the same page, depending on which organization they specified at login (user to organization is many-many). Users may also switch organizations without logging out, in which case the role stored in session is updated.

#5453 report it
seb at 2011/10/13 07:08am
dckurushin: Another solution

Sorry, my mistake was in the point 2. Actually I do not assign role after user loggs in, but in the auth manager init(). So point 2 should be:

2) Extend CPhpAuthManager and override init() method and assign the role to the user.

In the code it looks like this:

class PhpAuthManager extends CPhpAuthManager{
  public function init(){
    if($this->authFile===null){
        $this->authFile=Yii::getPathOfAlias('application.config.auth').'.php';
    }
parent::init();
$this->defaultRoles = array('guest'); if(!Yii::app()->user->isGuest){ $this->assign(Yii::app()->user->getRole(), Yii::app()->user->id); } } }

This solution is actually works in my current project. The main benefit over the CDbAuthManager is that I can edit RBAC hierarchy in the PHP file without having to call save() each time I change something. I think the CDbAuthManager is convenient only when you use some GUI where end-users can change RBAC hierarchy. In other cases, when hierarchy determined by the programmer then CPhpAuthManager is more convenient.

Edit. More detailed explanation of this approach is here. This is samdark's article in russian, but there are many code snippets and I think it should be clear how to use CPhpAuthManager in this way.

#5446 report it
dckurushin at 2011/10/12 03:16pm
seb : Another solution

You should remember that when you assign a role, if you not save it, the next time you go to another page - you have no role assigned.

To understand why just look at the checkAccess...

the assignments is an array built based on what saved in auth.php, so if no saving - no accessRights to the user!

So your solution won't work with CPhpAuthManager ...

It is interesting that yii has no CSessionAuthManager ... actually it is very common... but you can easly create one based on the CPhpAuthManager example


In second thought - if to assign the role from session in beforeAction at base controller or something...

#5445 report it
seb at 2011/10/12 03:01pm
Another solution

I think the problem here is not a CPhpAuthManager, but the suggested in the "How to setup RBAC with a php file" article way to use it. There is another approach:

1) Add "role" field to the user table

2) When user is logged in then read "role" field and assign that role to the user

3) Never call Yii::app()->authManager->save(), just edit auth.php file manually

This way the auth.php file will contain only declarations of roles, tasks and operations, but not assignments of roles to users. And the size of this file will not depend on the number of users.

Leave a comment

Please to leave your comment.

Write new article