1

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']]);
}
}
  • How are those rights stored currently? That is vital for a correct answer. Is it a "user_rights" table? – mark Dec 18 '13 at 12:00
  • Currently it's done in a canEditEvent, canAddProducts, isAdmin series of functions, that I call in my controller and then send to the view. But indeed I was thinking of an Auth helper, with a rights a table and a function returning the corresponding true/false and false if not found in the table. But I would like to know if it's the best way to do this, in the MVC idea. – nicolecoco02 Dec 18 '13 at 13:15

4 Answers4

2

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'));
}
floriank
  • 25,546
  • 9
  • 42
  • 66
  • Yes I think it's definitly the best option. It's a bit frustrating because it's exactly the same logic than the "isAuthorized" function. – nicolecoco02 Dec 18 '13 at 12:33
  • You can do this in the controller with something like `if ($this->Auth->role('admin')) { $this->set('admin', true); }` then check `$admin` in the view. But the `AuthHelper` seems a much better way to go. – Chuck Burgess Dec 18 '13 at 15:33
  • Well, you'll have to set it per role then and in the views you have to check like if (isset($admin) && $admin === true)). The helper helps to reduce the amount of code you have to write. Also it encapsulates the check logic. If you app needs something special just extend it and load your customized AuthHelper aliased as Auth helper. – floriank Dec 18 '13 at 16:51
1

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.

Raffaele
  • 20,627
  • 6
  • 47
  • 86
  • Thanks for your answer. I do check those rights. In fact the problem is not here, I'll try to be more clear. 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 you're right, but can I properly get it from the view ? – nicolecoco02 Dec 18 '13 at 12:28
  • The less logic in the view, the better. I think one possible approach would be checking user's rights in the `eventDetails` action, and sending the view a whitelist of actions that can be performed. This way the view doesn't have to query the authorization layer itself. The template then will check the whitelist to decide whether to draw the buttons. The whitelist can be an array of symbols, or just a bunch of boolean flags on your view, like `$canDoThis`, `$canDoThat` and so on – Raffaele Dec 18 '13 at 12:34
  • Oh not to bad. You mean I send a for example a key based list of the actions the logged user can perform and I check that doing a isset for example ? You think it's better than calling a custom helper ? – nicolecoco02 Dec 18 '13 at 12:36
  • Actually you can build your own Helper to implement the whitelist approach – Raffaele Dec 18 '13 at 14:33
  • Yeah this is what I did, I just check if the key exist in the whitelist so that it's a one line function. I'll edit the 1st post – nicolecoco02 Jan 08 '14 at 11:15
0

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.

Скач от
  • 212
  • 2
  • 14
-2

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!

Anubhav
  • 1,605
  • 4
  • 18
  • 31
  • 1
    Yeah I know I can call the controller but it's a very bad way to do that, I am really searching the best way to do that. Currently I call the function from my controller and I send the result to the view but it's getting more and more complicated with advanced rights – nicolecoco02 Dec 18 '13 at 11:42
  • Create one action in AppController, which will be called in beforAction() function and set your rights there.... – Anubhav Dec 18 '13 at 12:26
  • There is always room for improvement...there is nothing like best – Anubhav Dec 18 '13 at 12:28