php Symfony UserInterface正在序列化整个庞大的User实体

wbgh16ku  于 2023-09-29  发布在  PHP
关注(0)|答案(4)|浏览(120)

我们实现了AdvancedUserInterface来管理用户身份验证,但是由于某种原因,Symfony安全性序列化了整个User实体,而不仅仅是最少的必需字段(例如:idusernamepassword)。
根据文档,我们需要指定应该序列化的确切字段(然后忽略其余字段)。

class User implements AdvancedUserInterface, \Serializable {

    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->username,
            $this->password
        ));
    }
}

但是,尽管我们这样做,Symfony安全忽略了这个serialize()方法,仍然序列化整个实体。这会中断登录,因为对象变得太大而无法序列化和存储。

qxsslcnc

qxsslcnc1#

下面是它在Symfony 5.4和更高版本的www.example.com中如何工作的解释https://symfony.com/doc/5.4/security.html#understanding-how-users-are-refreshed-from-the-session。然而,他们提到了SerializableInterface,没有任何参考,很难找到任何关于它的东西。这样的接口不存在(PhpStorm无法找到它)。我猜他们可能是指https://www.php.net/manual/en/class.serializable.php
我通过在我的User实体中实现\Serializable接口解决了这个问题,如下所示:

# App\Entity\User

public function serialize()
{
    return serialize([
        'id' => $this->getId(),
        'password' => $this->getPassword(),
        'email' => $this->getEmail(),
        'userIdentifier' => $this->getEmail(),
        'username' => $this->getUsername(),
        'salt' => $this->getSalt(),
        'roles' => $this->getRoles(),
        'enabled' => $this->isEnabled(),
    ]);
}

public function unserialize($data)
{
    $unserialized = unserialize($data);

    $this
        ->setId($unserialized['id'])
        ->setPassword($unserialized['password'])
        ->setEmail($unserialized['email'])
        ->setRoles($unserialized['roles'])
        ->setEnabled($unserialized['enabled']);
}

我不再保存不需要的关系或数据。现在会议规模很小。我还注意到响应时间显著减少=登录用户的页面加载速度更快,特别是管理员。

xj3cbfub

xj3cbfub2#

显然,Symfony安全使用Symfony\Component\Security\Core\Authentication\Token\AbstractToken,这有一个自定义的序列化方法,可以将更多的数据添加到会话序列化的User中。

public function serialize()
{
    return serialize(
        array(
            is_object($this->user) ? clone $this->user : $this->user,
            $this->authenticated,
            $this->roles,
            $this->attributes,
        )
    );
}

这会将role添加到序列化对象。但是我们有一个自定义的角色系统,它与其他实体(例如Site),这会在序列化User时导致致命的膨胀。

5sxhfpxr

5sxhfpxr3#

我意识到这是一个老问题,但我使用Symfony序列化器解决了一个类似的问题。你可以在这里读到更多。
对组进行编码的函数如下所示:

public static function encodeCategory($objects)
{
    $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));

    $encoders = [new JsonEncoder()];
    $defaultContext = [
        AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) {
            if(method_exists($object,'getName'))
                return $object->getName();
        },
    ];

    $normalizers = [new ObjectNormalizer($classMetadataFactory, null, null, null, null, null, $defaultContext)];
    $serializer = new Serializer($normalizers,$encoders);

    return $serializer->serialize($objects,'json',['groups' => 'category']);
}

一个简单的实体示例如下:

class User 
{

    /**
    * @ORM\Id()
    * @ORM\GeneratedValue()
    * @ORM\Column(type="integer")
    * @Groups({"category"})
    */
    private $id;

    /**
    * @ORM\Column(type="string", length=255)
    * @Groups({"category"})
    */
    private $name;

    /**
    * @ORM\ManyToOne(targetEntity="App\Entity\Type", inversedBy="users")
    * @ORM\JoinColumn(nullable=false)
    * @Groups({"category"})
    */
    private $type;
}

以及Type实体:

class Type 
{
    /**
    * @ORM\Id()
    * @ORM\GeneratedValue()
    * @ORM\Column(type="integer")
    * @Groups({"category"})
    */
    private $id;

    /**
    * @ORM\Column(type="string", length=255)
    * @Groups({"category"})
    */
    private $name;

    /**
    * @ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="type")
    */
    private $users;
}

您可以根据需要将其扩展到任意多个实体,或创建新的组。现在使用函数:

$users = $this->getDoctrine()->getRepository(User::class)->findAll();
return new JsonResponse($this->encodeCategory($users));

在使用groups之前,我尝试了MaxDepth注解,但它似乎有some problems

rkue9o1l

rkue9o1l4#

https://symfony.com/doc/7.0/session.html#mariadb-mysql上的文档指出,对于sess_data列,我们可以使用MEDIUMBLOB而不是默认的BLOB
BLOB列类型(默认情况下由createTable()使用)最多存储64 kb。如果用户会话数据超过此值,则可能会引发异常,或者会以静默方式重置他们的会话。如果需要更多空间,请考虑使用MEDIUMBLOB。
您可以通过编写迁移来实现这一点(有关迁移,请参见https://symfony.com/doc/current/doctrine.html)。

相关问题