How to implement Role-based REST API How to implement Role-based REST API symfony symfony

How to implement Role-based REST API


If you are using JMSSerializer you can use groups to decide what can be seen or not. Then in your controller, or where ever, you could set the group based on the role.

For example with the mapping (in YAML)..

Fully\Qualified\Class\Name:    exclusion_policy: ALL    properties:        id:            groups: [user]        userAndAdmin:            groups: [user]        adminOnly:            groups: [admin]

And then in your controller you would set the group like...

public function getUsersAction(Request $request){    $users = $this->getRepository()->findAll();    $serializer = $this->get('jms_serializer.serializer');    $json = $serializer->serialize(        $users,        'json',        SerializationContext::create()->setGroups($this->generateGroups())    );    return new Response($json);    // If you are using FOSRestBundle, which I would recommend, then you would just need to do...    $view = $this        ->view($this->getRepository()->findAll();)        ->setExclusionGroups($this->generateGroups())    ;    return $this->handleView($view);}private function generateGroups(){    $securityContext = $this->get('security.context');    $groups = array();    if ($securityContext->isGranted('ROLE_USER')) {        $groups[] = 'user';    }    if ($securityContext->isGranted('ROLE_ADMIN')) {        $groups[] = 'admin';    }    return $groups;}

Although the whole "generateGroups" and setting the groups would be better placed in a customer view handler or response generator.

Assuming your hierarchy has ROLE_ADMIN as a parent of ROLE_USER you would get the following results.

ROLE_USER

{    "users": [        {            "id": 1,            "userAndAdmin": "val"        }    ]} 

ROLE_ADMIN

{    "users": [        {            "id": 1,            "userAndAdmin": "val",            "adminOnly": "val"        }    ]} 


Since the API is dependent on user who is making the request, each request will have to carry the information about the current user. Usually all authorization related tasks are processed within the controller. So, answer to your first question is that you should process the roles in the controller and based on the roles, you should filter out the fields from the data returned from the repository. For example,

//users is the array of user objects returned by your repositorydata = [];if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {  foreach($users as $user){  // Add ROLE_ADMIN specific data        data[][] = array(            'name' => $user->getName(),            'email' => $user->getEmail(),        );  }     }if ($this->get('security.context')->isGranted('ROLE_USER')) {   foreach($users as $user){    // Add ROLE_USER specific data    data[][] = array(        'name' => $user->getName(),        'address' => $user->getAddress(),               );   }   }

then, JSON encode the data array and return as the response. To reduce the number of queries, you can add a __toArray method in your User class.