The uniqueness issues and also an issue with inheritence has been solved in changset 5588
Important Update (2007-07-24) : Brian brought to my attention a problem with multiple actions that have the same name. This problem is due to an incorrect Sql query in db_acl.php. I have filed Trac Ticket #2976 which includes a patch, unit test and test fixtures.
So I’ve shown you how to create a User Model that can be used for ACL, but what is next?
The AuthComponent allows you to both authenticate and authorize your users in a relatively simple manner – once you know how. This took me a lot of source code digging, mail list browsing and googling to find the way that “just works”.
Setting up Aco’s, Aro’s and Permissions
First of, we need to have some Aro’s and Aco’s. Aro’s are the User model from above and are simple enough – you can get away with scaffolding if you want.
Aco’s took me a little longer to figure out. There are going to be controller action pairs, naturally, but the catch was how to put these into the database. It turns out that you need to have Controllers at one level, with actions children of there respective controllers. This might seem obvious but I was trying to save the actions with an alias of “controller/action” when they should just be “action”.
Your tree of Aco aliases should look like the following:
ROOT
|-Controller1
|-index
|-action1
|-action2
|-Controller2
|-index
|-action1
Pretty straight forward once you know how. This way the path can be followed down (or up actually) by the AclComponent. It also allows you to create wholesale permissions such as denying a whole controller by setting the permissions on the controller level.
Then all you need to do is grant Users access to actions. Because we are using User models the easist way is with a series of commands like:
$this->Acl->allow(array('model' => 'User', 'foreign_key' => $id), 'Controller1/action');
Using AuthComponent for Authentication
The AuthComponent is a really great tool and is very flexible. This post will only show one way to use it, but there are many other ways to put it to use.
First up, we will use AuthComponent for authentication. This part is pretty straight forward, but requires a little configuration. The best place to do this is in AppController::beforeFilter().
You need to include the AclComponent and the AuthComponent in AppController.
var $components = array('Acl', 'Auth');
It is very import that you include the AclComponent before the AuthComponent otherwise you will get this funky error message.
Fatal error: Call to a member function check() on a non-object in /var/www/geoff/cake/cake/libs/controller/components/acl.php on line 87
The reason for this is that Components are started in the order they appear in the $components list, and the AuthComponent does all its magic at startup, so when Auth tries to use Acl::check() there is no Acl.
For authentication we need to set the loginAction and loginRedirect properties.
function beforeFilter(){
if (isset($this->Auth)) {
$this->Auth->loginAction = '/users/login';
$this->Auth->loginRedirect = '/users/account';
}
}
You can also set the fields that are used for authentication if your user model does not use the default of ‘username’ and ‘password’.
$this->Auth->fields = array('username' => 'login_name', 'password' => 'p4sswrd');
It is worth noting that the AuthComponent will hash the password for security reasons. This is default behaviour and it can not be overriden. Where I got caught out (again) was that I had a before save on my user model that hashed the password in the same manner as AuthComponent. Do not hash your passwords at the model level if you have included the AuthComponet at the AppController level. The AuthComponent will hash it before it gets to your beforeSave and you will end up with double hashed passwords in the database and therefore unable to login.
Another good config option is the userScope property. It allows you to add other conditions to the authentication query, such as checking a disabled field.
$this->Auth->userScope = array('User.disabled' => 0);
Using AuthComponent for Authorization
So that was how to set your authentication. Setting up AuthComponet for authorization against ACL is actually easier. One extra line of code.
$this->Auth->authorize = 'actions';
This will use the User Aro’s created above that corresponds to the User just authenticated, and test it against the current controller and action. Surprisingly easy.
Final Result
The final AppController should look like:
class AppController extends Controller {
var $helpers = array('Html', 'Javascript', 'Form');
var $components = array('Acl', 'Auth');
var $publicControllers = array('pages');
function beforeFilter(){
if (isset($this->Auth)) {
$this->Auth->userScope = array('User.disabled' => 0);
$this->Auth->loginAction = '/users/login';
$this->Auth->loginRedirect = '/users/account';
$this->Auth->fields = array('username' => 'username', 'password' => 'passwrd');
$this->Auth->authorize = 'actions';
if (in_array(low($this->params['controller']), $this->publicControllers)) {
$this->Auth->allow();
}
}
}
}
$this->publicControllers allows you to assign controllers which do not require authentication or authorization. I mainly use it to grant access to the pages contoller.
Recent Comments