Question

I am using CakePHP in my project and I am looking for a proper way to check advanced user rights in my views.

I have several pages in which the contents depend of your rights (you can view some blocks or not, edit some infos or not, etc...)

I searched and the only way I found is to implement an Auth Helper, but I thought the best way to to that is to implement methods in my "UserController" (such as canPerformAction($action, $controller = 'default_controller')), am I wrong ? And if I'm right, how to call that methods properly ?

Thanks.

EDIT : More precisions

For example I have an action "editEventProducts" that a user can perform only if he's the event owner and if the event status is <= 2.

I check that in my controller "isAuthorized" function, works like a charm.

But I have a page called "eventDetails", form which you can perfom several actions such as this one, and I want to show the edit button, only if you can do it.

If fact what I need is the output of the "isAuthorized" function for each action that you can call, but can I properly get it from a view ?

Solution

I implemented a Auth helper who does several check such as this one, which is finally a whitelist check, depending of the status of my event, hope it will help, the code :

App::uses('AppHelper', 'View/Helper');

class AuthHelper extends AppHelper {

var $helpers = array('Session');

private $_whitelist = array(
    'controller1' => array(
        'events' => array(
            'action1'     => array(1 => true, 2 => true),
            'action2'     => array(1 => true, 2 => true),
            'action3'     => array(3 => true),
            'action4'     => array(6 => true)
        )
    ),
    'user'  => array(
        'controller1' => array(
            'action1'     => array(1 => true, 2 => true),
            'action2'     => array(1 => true, 2 => true)
        )
    )
);

public function canPerformAction ($action, $event_infos, $controller = 'events') {
    return isset($this->_whitelist[$this->Session->read('Auth.User.role')][$controller][$action][$event_infos['Event']['state_id']]);
}
}
Was it helpful?

Solution 2

What you need is called authorization, and is the process of granting/denying actions usually built on top of an authentication step, which maps HTTP requests to logical users.

The authorization scheme can be implemented in a number of ways, for example with simple role-based rules, where users are grouped exactly for the purpose of assigning rights, or with more complex ACL (access control lists). Both can be adopted at the same time for different parts of the system, depending on your needs.

Whatever scheme you pick, you absolutely need to query it at the beginning of your controllers actions (if applicable, you may and up with a standardized authorization filter in your AppController), because the HTTP request doesn't need to come from a previously sent HTTP page, but could be a (possibly) malicious, hand-craften one. Also, you'll likely need to adjust the UI after the user rights. Maybe you'll better start with a bunch of if statements, and then after some days of work you'll be able to identify your needs and build your libraries/helpers/blocks/whatever to avoid code duplication and easing reading the templates.

OTHER TIPS

It sounds to me like you just want to render some parts of a view based on the permissions of the user. Well, in this case I think a helper is the right choice. The user should already have all the permissions he has loaded - except they're very fine grained and you got thousands of permissions.

Check this AuthHelper, it allows you to check if the user is logged in, for a role or a set of roles in a field. Alternatively implement your own solution to match whatever your permission system is.

Note that the helper relies on passing the user data to the view in a view variable. It can be also configured to read the data from the auth part of the session directly.

Here is the example taken from it's documentation:

if ($this->Auth->isLoggedIn()) {
    echo __('Hello %s!', $this->Auth->user('username'));
}

if ($this->Auth->isMe($record['Record']['user_id']) {
    // or your edit button here
    echo '<h2>' . __('Your records') . '</h2>';
}

if ($this->Auth->hasRole('admin') {
    echo $this->Html->link(__('delete'), array('action' => 'delete'));
}

If you have predefined user permissions (like 'admin', 'moderator', 'editor', 'publisher'...) you can just read the user role and current action in the controller function isAuthorized and set it to true or false.

If you want custom permissions per user, you can store those values in the database, read them in the isAuthorized function and make your logic to determine if you should allow him or not.

My solution to this was a separate table user_permissions that was something like this:

user_id | action

where action would be `controller/action' or 'view/block' or whatever you want to save there.

I would read all values for current user in the controller and if the current controller/action was found in the array, i'd set isAuthorized to true. You can apply your logic to the blocks also.

You can call function of controller from view using

requestAction(string $url, array $options) 

Or you can create your custom Helper which will do this for you!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top