防止在 Symfony 会话中存储整个用户
Prevent storing entire user in Symfony session
我的应用程序正在使用 Symfony 5.4.2
并且依赖于新的 Authenticator Manager。
我最近遇到了与 session_open()
相关的内存错误。在调查时,我注意到整个用户实体都存储在会话文件中(作为 PHP serialize
d 字符串),以 _sf2_attributes|
.
开头
所以每个相关实体也都存储在那里(每个 属性、用户购买及其详细信息,等等),这可能非常重(我有超过 100 Kb 的会话文件,这对我来说听起来很大)。
这是预期的方式吗?
有没有办法防止序列化所有用户实体属性?
您必须序列化您的用户实体class实现\Serializable
接口并定义serialize
, unserialize
和 __sleep
方法,定义哪些属性将包含在会话中。使用 __sleep
您将允许只有特定属性进入序列化过程;例如:
/**
* Usuario
*
* @ORM\Table(name="usuario", uniqueConstraints={@ORM\UniqueConstraint(name="usuario_username_uniq", columns={"username"})}, indexes={@ORM\Index(name="usuario_rol_idx", columns={"rol_id"}), @ORM\Index(name="usuario_nodo_idx", columns={"estructura_organizativa_id"}), @ORM\Index(name="usuario_id_publico_idx", columns={"id_publico"})})
* @ORM\Entity(repositoryClass="App\Repository\UsuarioRepository")
* @UniqueEntity("username", message="Ya existe un usuario con ese identificador")
*/
class Usuario implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface, \Serializable
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\SequenceGenerator(sequenceName="usuario_id_id_seq", initialValue=1, allocationSize=100)
*/
private $id;
/**
* @var string
*
* @Assert\NotBlank(message="El identificador es obligatorio.")
* @ORM\Column(name="username", type="string", unique=true, length=100, nullable=false)
*/
private $username;
/**
* @var string
*
* @Assert\NotBlank(message="El nombre es obligatorio.")
* @ORM\Column(name="nombre_completo", type="string", length=255, nullable=false)
*/
private $nombreCompleto;
/**
* @var string
*
* @Assert\Length(
* min=6,
* max=255,
* minMessage="La contraseña debe tener como mínimo {{ limit }} caracteres",
* maxMessage="La contraseña no puede exceder los {{ limit }} caracteres."
* )
* @ORM\Column(name="password", type="string", length=255, nullable=false)
*/
private $password;
/**
* @var boolean
*
* @ORM\Column(name="activo", type="boolean", nullable=false)
*/
private $activo;
/**
* @var type \App\Entity\Rol
*
* @ORM\ManyToOne(targetEntity="Rol", fetch="EAGER")
* @ORM\JoinColumn(name="rol_id", referencedColumnName="id", nullable=false, onDelete="RESTRICT")
*/
private $rol;
/**
* Constructor
*/
public function __construct()
{
$this->activo = true;
}
/**
* Set username
*
* @param string $username
* @return Usuario
*/
public function setUsername(?string $username): self
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* Set nombreCompleto
*
* @param string $nombreCompleto
* @return Usuario
*/
public function setNombreCompleto(string $nombreCompleto): self
{
$this->nombreCompleto = $nombreCompleto;
return $this;
}
/**
* Get nombreCompleto
*
* @return string
*/
public function getNombreCompleto(): string
{
return $this->nombreCompleto;
}
/**
*
* @return array
*/
public function getRoles(): array
{
$coleccion = new ArrayCollection();
$coleccion->add($this->getRol()->getToken());
$coleccion[] = "ROLE_USER";
return array_unique($coleccion->toArray());
}
/**
* Set password
*
* @param string $password
* @return Usuario
*/
public function setPassword(?string $password): self
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* Set activo
*
* @param bool $activo
* @return Usuario
*/
public function setActivo(bool $activo): self
{
$this->activo = $activo;
return $this;
}
/**
* Get activo
*
* @return bool
*/
public function getActivo(): bool
{
return $this->activo;
}
/**
* Get id
*
* @return integer
*/
public function getId(): ?int
{
return $this->id;
}
/**
*
* @return void
*/
public function eraseCredentials(): void
{
}
/**
*
* @return string
*/
public function getSalt(): string
{
return '';
}
/**
*
* @return bool
*/
public function isAccountNonExpired(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isAccountNonLocked(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isCredentialsNonExpired(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isEnabled(): bool
{
return $this->activo;
}
/**
*
* @return string
*/
public function serialize(): string
{
return serialize([
$this->username,
$this->nombreCompleto,
$this->password,
$this->activo,
$this->id,
$this->idPublico
]);
}
/**
*
* @param type $serialized
* @return void
*/
public function unserialize($serialized): void
{
list(
$this->username,
$this->nombreCompleto,
$this->password,
$this->activo,
$this->id,
$this->idPublico
) = unserialize($serialized);
}
/**
*
* @return array
*/
public function __sleep(): array
{
return ['username', 'nombreCompleto', 'password', 'activo', 'id', 'idPublico'];
}
/**
*
* @return string
*/
public function __toString(): string
{
return $this->nombreCompleto;
}
/**
*
* @param UserInterface $user
* @return bool
*/
public function isEqualTo(UserInterface $user): bool
{
if ($this->getUsername() === $user->getUsername() && $this->getPassword() === $user->getPassword() && $this->getSalt() === $user->getSalt()) {
return true;
}
return false;
}
/**
* @return string
* * */
public function getUserIdentifier(): string
{
return (string) $this->username;
}
}
我的应用程序正在使用 Symfony 5.4.2
并且依赖于新的 Authenticator Manager。
我最近遇到了与 session_open()
相关的内存错误。在调查时,我注意到整个用户实体都存储在会话文件中(作为 PHP serialize
d 字符串),以 _sf2_attributes|
.
所以每个相关实体也都存储在那里(每个 属性、用户购买及其详细信息,等等),这可能非常重(我有超过 100 Kb 的会话文件,这对我来说听起来很大)。
这是预期的方式吗?
有没有办法防止序列化所有用户实体属性?
您必须序列化您的用户实体class实现\Serializable
接口并定义serialize
, unserialize
和 __sleep
方法,定义哪些属性将包含在会话中。使用 __sleep
您将允许只有特定属性进入序列化过程;例如:
/**
* Usuario
*
* @ORM\Table(name="usuario", uniqueConstraints={@ORM\UniqueConstraint(name="usuario_username_uniq", columns={"username"})}, indexes={@ORM\Index(name="usuario_rol_idx", columns={"rol_id"}), @ORM\Index(name="usuario_nodo_idx", columns={"estructura_organizativa_id"}), @ORM\Index(name="usuario_id_publico_idx", columns={"id_publico"})})
* @ORM\Entity(repositoryClass="App\Repository\UsuarioRepository")
* @UniqueEntity("username", message="Ya existe un usuario con ese identificador")
*/
class Usuario implements UserInterface, PasswordAuthenticatedUserInterface, EquatableInterface, \Serializable
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\SequenceGenerator(sequenceName="usuario_id_id_seq", initialValue=1, allocationSize=100)
*/
private $id;
/**
* @var string
*
* @Assert\NotBlank(message="El identificador es obligatorio.")
* @ORM\Column(name="username", type="string", unique=true, length=100, nullable=false)
*/
private $username;
/**
* @var string
*
* @Assert\NotBlank(message="El nombre es obligatorio.")
* @ORM\Column(name="nombre_completo", type="string", length=255, nullable=false)
*/
private $nombreCompleto;
/**
* @var string
*
* @Assert\Length(
* min=6,
* max=255,
* minMessage="La contraseña debe tener como mínimo {{ limit }} caracteres",
* maxMessage="La contraseña no puede exceder los {{ limit }} caracteres."
* )
* @ORM\Column(name="password", type="string", length=255, nullable=false)
*/
private $password;
/**
* @var boolean
*
* @ORM\Column(name="activo", type="boolean", nullable=false)
*/
private $activo;
/**
* @var type \App\Entity\Rol
*
* @ORM\ManyToOne(targetEntity="Rol", fetch="EAGER")
* @ORM\JoinColumn(name="rol_id", referencedColumnName="id", nullable=false, onDelete="RESTRICT")
*/
private $rol;
/**
* Constructor
*/
public function __construct()
{
$this->activo = true;
}
/**
* Set username
*
* @param string $username
* @return Usuario
*/
public function setUsername(?string $username): self
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* Set nombreCompleto
*
* @param string $nombreCompleto
* @return Usuario
*/
public function setNombreCompleto(string $nombreCompleto): self
{
$this->nombreCompleto = $nombreCompleto;
return $this;
}
/**
* Get nombreCompleto
*
* @return string
*/
public function getNombreCompleto(): string
{
return $this->nombreCompleto;
}
/**
*
* @return array
*/
public function getRoles(): array
{
$coleccion = new ArrayCollection();
$coleccion->add($this->getRol()->getToken());
$coleccion[] = "ROLE_USER";
return array_unique($coleccion->toArray());
}
/**
* Set password
*
* @param string $password
* @return Usuario
*/
public function setPassword(?string $password): self
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* @return string
*/
public function getPassword(): string
{
return $this->password;
}
/**
* Set activo
*
* @param bool $activo
* @return Usuario
*/
public function setActivo(bool $activo): self
{
$this->activo = $activo;
return $this;
}
/**
* Get activo
*
* @return bool
*/
public function getActivo(): bool
{
return $this->activo;
}
/**
* Get id
*
* @return integer
*/
public function getId(): ?int
{
return $this->id;
}
/**
*
* @return void
*/
public function eraseCredentials(): void
{
}
/**
*
* @return string
*/
public function getSalt(): string
{
return '';
}
/**
*
* @return bool
*/
public function isAccountNonExpired(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isAccountNonLocked(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isCredentialsNonExpired(): bool
{
return true;
}
/**
*
* @return bool
*/
public function isEnabled(): bool
{
return $this->activo;
}
/**
*
* @return string
*/
public function serialize(): string
{
return serialize([
$this->username,
$this->nombreCompleto,
$this->password,
$this->activo,
$this->id,
$this->idPublico
]);
}
/**
*
* @param type $serialized
* @return void
*/
public function unserialize($serialized): void
{
list(
$this->username,
$this->nombreCompleto,
$this->password,
$this->activo,
$this->id,
$this->idPublico
) = unserialize($serialized);
}
/**
*
* @return array
*/
public function __sleep(): array
{
return ['username', 'nombreCompleto', 'password', 'activo', 'id', 'idPublico'];
}
/**
*
* @return string
*/
public function __toString(): string
{
return $this->nombreCompleto;
}
/**
*
* @param UserInterface $user
* @return bool
*/
public function isEqualTo(UserInterface $user): bool
{
if ($this->getUsername() === $user->getUsername() && $this->getPassword() === $user->getPassword() && $this->getSalt() === $user->getSalt()) {
return true;
}
return false;
}
/**
* @return string
* * */
public function getUserIdentifier(): string
{
return (string) $this->username;
}
}