* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Security\Core\Authentication\Token; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Core\User\UserInterface; /** * Base class for Token instances. * * @author Fabien Potencier * @author Johannes M. Schmitt */ abstract class AbstractToken implements TokenInterface, \Serializable { private ?UserInterface $user = null; private array $roleNames = []; private array $attributes = []; /** * @param string[] $roles An array of roles * * @throws \InvalidArgumentException */ public function __construct(array $roles = []) { foreach ($roles as $role) { $this->roleNames[] = $role; } } public function getRoleNames(): array { return $this->roleNames; } public function getUserIdentifier(): string { return $this->user ? $this->user->getUserIdentifier() : ''; } public function getUser(): ?UserInterface { return $this->user; } /** * @return void */ public function setUser(UserInterface $user) { $this->user = $user; } /** * @return void */ public function eraseCredentials() { if ($this->getUser() instanceof UserInterface) { $this->getUser()->eraseCredentials(); } } /** * Returns all the necessary state of the object for serialization purposes. * * There is no need to serialize any entry, they should be returned as-is. * If you extend this method, keep in mind you MUST guarantee parent data is present in the state. * Here is an example of how to extend this method: * * public function __serialize(): array * { * return [$this->childAttribute, parent::__serialize()]; * } * * * @see __unserialize() */ public function __serialize(): array { return [$this->user, true, null, $this->attributes, $this->roleNames]; } /** * Restores the object state from an array given by __serialize(). * * There is no need to unserialize any entry in $data, they are already ready-to-use. * If you extend this method, keep in mind you MUST pass the parent data to its respective class. * Here is an example of how to extend this method: * * public function __unserialize(array $data): void * { * [$this->childAttribute, $parentData] = $data; * parent::__unserialize($parentData); * } * * * @see __serialize() */ public function __unserialize(array $data): void { [$user, , , $this->attributes, $this->roleNames] = $data; $this->user = \is_string($user) ? new InMemoryUser($user, '', $this->roleNames, false) : $user; } public function getAttributes(): array { return $this->attributes; } /** * @return void */ public function setAttributes(array $attributes) { $this->attributes = $attributes; } public function hasAttribute(string $name): bool { return \array_key_exists($name, $this->attributes); } public function getAttribute(string $name): mixed { if (!\array_key_exists($name, $this->attributes)) { throw new \InvalidArgumentException(\sprintf('This token has no "%s" attribute.', $name)); } return $this->attributes[$name]; } /** * @return void */ public function setAttribute(string $name, mixed $value) { $this->attributes[$name] = $value; } public function __toString(): string { $class = static::class; $class = substr($class, strrpos($class, '\\') + 1); $roles = []; foreach ($this->roleNames as $role) { $roles[] = $role; } return \sprintf('%s(user="%s", roles="%s")', $class, $this->getUserIdentifier(), implode(', ', $roles)); } /** * @internal */ final public function serialize(): string { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); } /** * @internal */ final public function unserialize(string $serialized): void { $this->__unserialize(unserialize($serialized)); } }