7

I would like to hear your thoughts about the task I have in front of me. Also if there is any known design pattern for this, a share would do a lot.

The task is to create the architecture of the project.

There will be several types of users :

  • normal user
  • supervisor
  • administrator
  • custom (here is the tricky part)

When they open the webpage I need to return every module (page) the user has access to.

I was thinking of polymorphism. I will have a base user which has permissions as protected property and every new class, for ex. supervisor, will add some more or overwrite the base ones.

Every module has components (parts of the webpage) and the result of the get will be something like this

$modulesAccess = [
     'baseModel' => array(
         'componentOne',
         'componentTwo',
     ),
]

With this the front-end developers will know what exactly to draw.

I was thinking to make these models/components in the database but it is going to be easier to manage them through the code. And polymorphism does good enough job for us there.

The tricky part, custom user. The idea is every Model/Component will have a different ajax request to return specific data. And every upper level user must implement it differently. That is fine, but the custom user, lets say for example is a supervisor, he needs to have access to only one Model/Component from the administrator.

How would you handle this?

Thank you in advance.

Thamilhan
  • 13,040
  • 5
  • 37
  • 59
Vasil Rashkov
  • 1,818
  • 15
  • 27
  • 2
    I think it's easier to do in on database level with [Role-Based Access Control](http://stackoverflow.com/questions/16139712/how-to-design-a-hierarchical-role-based-access-control-system). – TheDrot Jun 07 '16 at 11:53
  • You can use access control lists and a link manager class to build user roles based on the pages that are available. Any new custom user can be build using the link manager. Within the link manager you can create categories with links that a user can select from based on their role. In this case you can use an order id where a user with lower level access cannot select priveleges with a higher order id. – Nitin Jun 16 '16 at 01:01

4 Answers4

9

An empirical approach is to structure Authentication and Authorization in following main models:

  • User: represents a user.
  • Group/Role: represents a group of users. In some cases user's role.
  • Module: represents your module, just encapsulates its definition information.
  • Permission: represents a permission and a "CRUD" operation (create, read, update, delete)

This can satisfy most of your security scenarios. For example:

  • GET all Modules that a particular User has "View" Permission.
  • GET all Modules that Supervisors have "View" Permission.

Plus you can:

  • Add/remove a specific User to/from a Group.
  • and more...

Polymorphism is not good to be used to form types of user. Instead, use Group or Role.

Chris Forrence
  • 10,042
  • 11
  • 48
  • 64
Robo
  • 612
  • 3
  • 7
3

With decorator pattern your code would not be required to extend the original class when you are adding new features as it allows functionality to be divided between classes with unique areas of concerns.

class AuthProvider
{

    protected $target = null;
    protected $acl = null;

    public function __construct( $target, $acl )
    {
        $this->target = $target;
        $this->acl = $acl;
    }

    public function __call( $method, $arguments )
    {
        if ( 
             method_exists( $this->target, $method )
          && $this->acl->isAllowed( get_class($this->target), $method )
        ){
            return call_user_func_array( 
                array( $this->target, $method ),
                $arguments
            );
        }
    }

}

and then call it like this

// Based on your: $current_User and $controller 
$acl = new AccessControlList( $current_User );

$controller = new AuthProvider( $controller, $acl );
// you can execute all the methods you had in previous controller 
// only now they will be checked against ACL
$controller->actionIndex();

When accessing the method check if they are allowed to execute based on their access rights.

As far as your question to tackle AJAX calls to Controller/Model is concerned. I would let controller handle the AJAX calls and based on access rights call the model and return the response. Calling Models via AJAX simply bypasses the controller which should be avoided.

Ashish Nayyar
  • 560
  • 3
  • 10
1

try to not reinvent the wheel, look for a framework or library that already solved the problem for you, your problem its simple and already solved...

you need basically 2 classes, a user, and a role, roles can be grouped en a tree.

so,lets say you have 3 pages, one for admin only, one for supervisors and one for every one,

you define you role trees this way

ROLE_ADMIN
   |- ROLE_SUPERVISOR
      |-ROLE_USER

and then... asign roles to your users...

the best part it's the flexibility, you can make your tree as granular as you may want, and even generate customs roles with many comvination...

a library implementing this model is: http://symfony.com/doc/current/components/security/index.html

wich is part of symfony framework, the library has many other features that you could find usefull, like, voters for example.

Javier Neyra
  • 1,239
  • 11
  • 12
1

Take a look at the Proxy Pattern which is a Design Pattern by GoF.

The Proxy Pattern is designed for access control.

When the client makes a request, it is forwarded through the Proxy, which would contain your permission checks and access control. If the request is valid, the results would be returned from the RealSubject through the Proxy.

Check out the Proxy in PHP

Igoranze
  • 1,506
  • 13
  • 35