5
votes

I'm building an Admin panel in Symfony 3 based on Roles & Permissions. Each admin will be assigned a role(or multiple roles) and then he will be able to do things based on the permissions assigned to that role.


To give you an idea, here's an example:

  • Admin panel has the functionality to add users, edit users and delete users.
  • I created a role: USER_MANAGEMENT_WITHOUT_DELETE which has permission to user_create and user_edit.
  • I created USER_MANAGEMENT_WITH_DELETE role which has permission to user_create, user_edit and user_delete
  • So now, admin with role USER_MANAGEMENT_WITH_DELETE can add, edit and delete the users where as admin with role USER_MANAGEMENT_WITHOUT_DELETE can only add and edit users but cannot delete them.

I searched and found out about FOSUserBundle and ACL. Some recommended ACL while others say it's better to use FOSUserBunder

I also read the documentation of FOSUserBunder and how it store Roles in roles column, something like a:1:{i:0;s:10:"ROLE_ADMIN";}, but there is nothing mentioned about permissions. So here are my queries:

  1. I'm confused between the two. Which one should i use?
  2. If i use FOSUserBunder, how to manage permissions?
1

1 Answers

7
votes

Roles are not specific tu FOSUserBundle. They are in Symfony.

ACLs are more complex than using roles. So I would suggest to use roles.

From the Symfony documentation : Alternatives to ACLs

Using ACL's isn't trivial, and for simpler use cases, it may be overkill. If your permission logic could be described by just writing some code (e.g. to check if a Blog is owned by the current User), then consider using voters. A voter is passed the object being voted on, which you can use to make complex decisions and effectively implement your own ACL. Enforcing authorization (e.g. the isGranted part) will look similar to what you see in this entry, but your voter class will handle the logic behind the scenes, instead of the ACL system.

To deal with 'permissions', I would sugget to use Voters :

First of all create a voter like this :

Configuration :

# app/config/services.yml
services:
    app.user_permissions:
        class: AppBundle\Voters\UserPermissionsVoter
        arguments: ['@security.access.decision_manager']
        tags:
            - { name: security.voter }
        public: false

And the class :

namespace AppBundle\Voters;

use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class UserPermissionsVoter extends Voter
{
    const USER_CREATE = 'user_create';
    const USER_EDIT = 'user_edit';
    const USER_DELETE = 'user_delete';

    private $decisionManager;

    public function __construct($decisionManager)
    {
        $this->decisionManager = $decisionManager;
    }

    protected function supports($attribute, $object)
    {    
        if (!in_array($attribute, array(self::USER_CREATE,self::USER_EDIT,self::USER_DELETE))) {
            return false;
        }

        return true;
    }

    protected function voteOnAttribute($attribute, $object, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof UserInterface) {
            return false;
        }

        switch($attribute) {
            case self::USER_CREATE:
                if ($this->decisionManager->decide($token, array('ROLE_USER_MANAGEMENT_WITH_DELETE'))
                    || $this->decisionManager->decide($token, array('USER_MANAGEMENT_WITHOUT_DELETE'))
                ){
                    return true;
                }
            break;
            case self::USER_EDIT:
                // ...
            break;
            case self::USER_DELETE:
                // ...
            break;
        }

        return false;
    }
}

Then you can check for permission in your controller :

userCreateAction()
{
    if(!$this->isGranted('user_create')){throw $this->createAccessDeniedException('You are not allowed to create an user.');}

    // next steps ...
}