Skip to content

Commit

Permalink
-api user detail, -user voter
Browse files Browse the repository at this point in the history
  • Loading branch information
joeymasip committed Jan 22, 2019
1 parent d0c833d commit 9630713
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/Controller/Api/ApiUserController.php
@@ -0,0 +1,41 @@
<?php

namespace App\Controller\Api;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

/**
* @Route("/user")
*/
class ApiUserController extends AbstractController
{
/**
* @Route("/{id}", name="api_user_detail", methods={"GET"})
* @param User $user
* @return JsonResponse
*/
public function detail(User $user)
{
$this->denyAccessUnlessGranted('view', $user);
return new JsonResponse($this->serialize($user), 200);
}

protected function serialize(User $user)
{
$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];

$serializer = new Serializer($normalizers, $encoders);

$json = $serializer->serialize($user, 'json');

return $json;
}
}
84 changes: 84 additions & 0 deletions src/Security/UserVoter.php
@@ -0,0 +1,84 @@
<?php

namespace App\Security;

use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;

class UserVoter extends Voter
{
// these strings are just invented: you can use anything
const VIEW = 'view';
const EDIT = 'edit';

private $decisionManager;

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

protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, array(self::VIEW, self::EDIT))) {
return false;
}

// only vote on User objects inside this voter
if (!$subject instanceof User) {
return false;
}

return true;
}

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

if (!$user instanceof User) {
// the user must be logged in; if not, deny access
return false;
}

// ROLE_SUPER_ADMIN can do anything! The power!
if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) {
return true;
}

// you know $subject is a User object, thanks to supports
/** @var User $userSubject */
$userSubject = $subject;

switch ($attribute) {
case self::VIEW:
return $this->canView($userSubject, $user);
case self::EDIT:
return $this->canEdit($userSubject, $user);
}

throw new \LogicException('This code should not be reached!');
}

private function canView(User $userSubject, User $user)
{
// if they can edit, they can view
if ($this->canEdit($userSubject, $user)) {
return true;
}

// the User object could have, for example, a method isPrivate()
// that checks a boolean $private property
return $user === $userSubject;
}

private function canEdit(User $userSubject, User $user)
{
// this assumes that the data object has a getOwner() method
// to get the entity of the user who owns this data object
return $user === $userSubject;
}
}

0 comments on commit 9630713

Please sign in to comment.