Reputation: 1064
I am developing a Symfony app with a REST API integrated but I'm facing a problem, when returning an user entity as JSON through an API request it returns the user password and despite being encrypted I would like to avoid it.
My user entity is:
<?php
namespace AppBundle\Entity;
use AppBundle\Util\Language;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
/**
* @ORM\Table(name="users")
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable
{
public function __construct()
{
$this->isActive = true;
}
// Functions and parameters
/**
* Set password
*
* @param string $password
*
* @return User
*/
public
function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
// More functions and parameters
/** @see \Serializable::serialize() */
public
function serialize()
{
return serialize(array(
$this->id,
$this->username,
$this->password,
$this->isActive,
$this->createdAt,
$this->lastLogin,
));
}
/** @see \Serializable::unserialize() */
public
function unserialize($serialized)
{
list (
$this->id,
$this->username,
$this->password,
$this->isActive,
$this->createdAt,
$this->lastLogin,
) = unserialize($serialized);
}
}
The User repository
<?php
namespace AppBundle\Repository;
use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository implements UserLoaderInterface
{
public function loadUserByUsername($username)
{
return $this->createQueryBuilder('u')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery()
->getOneOrNullResult();
}
}
I have an static method to build API responses
public static function createSuccessfulresponse($entity, $entityName, $responseCode, $userLocale = "en", $responseMsg = "")
{
$defResponseMsg = ($responseMsg != "" ? $responseMsg : ApiResponseCode::getMsg($responseCode, $userLocale));
$responseArray = array();
$responseArray['responseCode'] = $responseCode;
$responseArray['responseMsg'] = $defResponseMsg;
$responseArray['userLocale'] = $userLocale;
if ($entity != null) {
$responseArray[$entityName] = $entity;
}
return ApiResponseHelper::serializeResponse($responseArray);
}
The response serializer
private static function serializeResponse($responseArray)
{
$encoders = array(new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
return $serializer->serialize($responseArray, 'json');
}
And one of the API calls which returns an user
entity (there are more)
/**
* @Route("/api/url/{uid}" )
* @Method({"GET"})
*/
public function getByUidAction($uid)
{
$user = $this->get('security.token_storage')->getToken()->getUser();
$entityManager = $this->getDoctrine()->getManager();
$entity = $entityManager->getRepository('AppBundle:Workday')->findOneBy(['uid' => $uid, 'user' => $user]);
if($entity != null){
return new Response(ApiResponseHelper::createSuccessfulresponse($entity, "workday", ApiResponseCode::SUCCESS_FETCH_WORKDAY, $user->getLocale()));
}else{
return new Response(ApiResponseHelper::createSuccessfulresponse(null, "workday", ApiResponseCode::ERROR_EXISTS_WORKDAY, $user->getLocale()));
}
}
This is one JSON response from the above method
{
"responseCode": "successfulResponseCode",
"responseMsg": "Data received",
"userLocale": "es",
"workday": {
"id": 10,
... so many data
"job": {
"id": 11,
.. more json data
},
"user": {
"username": "amendez",
"password": "encrypted_password",
... more data
},
... and more data
}
}
As you can see I receive a JSON object with the user which contains its encrypted password and many other data, my goal is to avoid returning the password key and value.
Does somebody know how could I achieve it?
Upvotes: 2
Views: 936
Reputation: 18416
You would need to define the Serializer groups with the desired getters assigned. See: https://symfony.com/doc/current/components/serializer.html#attributes-groups.
The preferred (best-practice) method would be to assign the desired groups.
use Symfony\Component\Serializer\Annotation\Groups;
class User implements AdvancedUserInterface, \Serializable
{
/**
* @Groups({"api"})
* @return string
*/
public function getUsername()
{
return $this->username;
}
//...
/**
* Get password
* @return string
*/
public function getPassword()
{
return $this->password;
}
}
Edited for easier use of Serializer service
In your app/config/config.yml
enable annotations, which in-turn enables the serializer service.
#config.yml
framework:
#...
serializer:
enable_annotations: true
Now you can call the Serializer service directly or use DI in your custom services.
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\HttpFoundation\JsonResponse;
private static function serializeResponse($responseArray)
{
$serializer = $this->container->get('serializer');
return $serializer->serialize($responseArray, JsonEncoder::FORMAT, array(
'groups' => array('api'),
'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS
));
}
To manually use the Serializer Component with groups.
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
private static function serializeResponse($responseArray)
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new ObjectNormalizer($classMetadataFactory);
$encoder = new JsonEncoder();
$serializer = new Serializer(array($normalizer), array($encoder));
return $serializer->serialize($responseArray, JsonEncoder::FORMAT, array('groups' => array('api')));
}
Alternatively you should be able to set it as part of the ignored attributes. See: https://symfony.com/doc/current/components/serializer.html#ignoring-attributes
private static function serializeResponse($responseArray)
{
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('password'));
$encoder = new JsonEncoder();
$serializer = new Serializer(array($normalizer), array($encoder));
return $serializer->serialize($responseArray, JsonEncoder::FORMAT);
}
Upvotes: 2