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.