Search code examples
symfony4fosuserbundlejmsserializerbundlesymfony-4.3

How to exclude password field from the user entity with JMS serializer using FOS User Bundle and Symfony 4?


I have implemented simple API with login functionality using FOSUserBundle and JWT (using LexikJWTAuthenticationBundle). All works well and I can login and get a jwt token. But when I created API endpoint to get user details the password field is sent in the response as well.

My controller method for fetching user details looks like this:

/**
 * @Route("/get/{id}", name="api_auth_get_user_by_id",  methods={"GET"})
 *
 * @param Request              $request
 * @param UserManagerInterface $userManager
 *
 * @return JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
 */
public function getById(SystemUser $user)
{
    return $this->handleView($this->view($user));
}

My user entity looks like this:

<?php

namespace App\Entity\Api\Auth;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;

/**
 * @ORM\Entity
 * @ORM\Table(name="fos_user")
 */
class SystemUser extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    public function __construct()
    {
        parent::__construct();
        // your own logic
    }
}

So as you can see my SystemUser entity extends from BaseUser entity which is found in FOSUserBundle.

This is how response JSON looks like when I get the user details from the API:

{
    "id": 1,
    "username": "test",
    "username_canonical": "test",
    "email": "[email protected]",
    "email_canonical": "[email protected]",
    "enabled": true,
    "password": "$2y$13$DnyFxYyJXQe3Z7chsJYwe.LUsuOWPqBtFm5.O0vwldX5AoMGld9ca",
    "last_login": "2019-08-27T06:19:43-04:00",
    "groups": [],
    "roles": []
}

So how can I exclude password property from the response. I am using latest Symfony 4.3. I know that in earlier versions of Symfony you could create a jms serializer config for each entity in your bundle but so much changed in Symfony 4 and now using bundles is not necessary and I am not using bundle for this simple app.


Solution

  • Correct way to exclude password property from entity that extends FOS User Bundle User entity is to configure packages/jms_serializer.yaml configuration like this:

    jms_serializer:
        metadata:
            auto_detection: true
            directories:
                FOSUB:
                    namespace_prefix: 'FOS\UserBundle'
                    path: '%kernel.root_dir%/serializer' 
    

    Also note that namespace_prefix must use single \ as this will NOT WORK:

    namespace_prefix: 'FOS\\UserBundle'
    

    Second step is to create JMS serialization file for FOS User entity specifically like this:

    FOS\UserBundle\Model\User:
        exclusion_policy: ALL
        properties:
            id:
                expose: true
            username:
                expose: true
            password:
                expose: false
            email:
                expose: true
            last_login:
                expose: true
            enabled:
                expose: true
    

    which can be saved in src/serializer/Model.User.yml

    One thing that was confusing me is that you can not configure serialization properties for parent class in configuration file for child class.

    For example if you are to extend FOS\UserBundle\Model\User entity with another entity SystemUser and you create serialization configuration file for that new entity in src/serialization/Entity.SystemUser.yml. From that Entity.SystemUser.yml file you CAN NOT exclude or configure any properties that are part of
    FOS\UserBundle\Model\User entity. For each parent class entity you must create its own serialization config file.

    Also don't forget to clear the cache after you changing serialization config.