Невозможно обновить токен, поскольку пользователь изменил Syfmony 4 - проблема EquatableInterface - PullRequest
0 голосов
/ 10 июня 2019

Я сделал форму входа в систему с Руководством по безопасности. Когда я пытаюсь войти, у меня есть журналы, как показано ниже:

2019-06-10 10:16:56] security.INFO: User has been authenticated successfully. {"username":"user@example.com"} []
[2019-06-10 10:16:56] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
[2019-06-10 10:16:56] request.INFO: Matched route "app_user_dashboard". {"route":"app_user_dashboard","route_parameters":{"_route":"app_user_dashboard","_controller":"App\\Controller\\User\\UserController::dashboard"},"request_uri":"https://127.0.0.1:8001/app/dashboard","method":"GET"} []
[2019-06-10 10:16:56] security.DEBUG: Read existing security token from the session. {"key":"_security_main","token_class":"Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken"} []
[2019-06-10 10:16:57] doctrine.DEBUG: SELECT t0.id AS id_1, t0.password AS password_2, t0.email AS email_3, t0.first_name AS first_name_4, t0.last_name AS last_name_5, t0.username AS username_6, t0.referral_code AS referral_code_7, t0.referred_by_code AS referred_by_code_8, t0.roles AS roles_9, t0.active_to AS active_to_10, t0.created_at AS created_at_11, t0.updated_at AS updated_at_12 FROM users t0 WHERE t0.id = ? [15] []
[2019-06-10 10:16:57] security.DEBUG: Cannot refresh token because user has changed. {"username":"user@example.com","provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider"} []
[2019-06-10 10:16:57] security.DEBUG: Token was deauthenticated after trying to refresh it. [] []

, а также я использую EquatableInterface. Мой User.php код:


namespace App\Entity\User;

use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Exception;
use Serializable;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * Class User
 *
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="App\Repository\User\UserRepository")
 * @ORM\HasLifecycleCallbacks
 *
 * @ORM\Entity
 * @UniqueEntity(fields="username", message="username taken")
 * @UniqueEntity(fields="email", message="email taken")
 */
class User implements UserInterface, Serializable, EquatableInterface
{
    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=256)
     */
    private $password;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=64, unique=true)
     */
    private $email;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", length=64, nullable=true)
     */
    private $firstName;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", length=64, nullable=true)
     */
    private $lastName;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=64, unique=true)
     */
    private $username;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=64, unique=true)
     */
    private $referralCode;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", length=64, nullable=true)
     */
    private $referredByCode;

    /**
     * @var array
     *
     * @ORM\Column(type="array", length=64)
     */
    private $roles;

    /**
     * @var DateTime
     *
     * @ORM\Column(type="datetime")
     */
    private $activeTo;

    /**
     * @var DateTime
     *
     * @ORM\Column(type="datetime")
     */
    private $createdAt;

    /**
     * @var DateTime
     *
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $updatedAt;

    /**
     * User constructor.
     *
     * @throws Exception
     */
    public function __construct()
    {
        $this->createdAt = new DateTime();
        $this->updatedAt = new DateTime();
        $this->activeTo = new DateTime('now + 14 days');
        $this->referralCode = substr(hash('sha256', uniqid()), 0, 5);
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return $this->getUsername();
    }

    /**
     * @return int
     */
    public function getId(): int
    {
        return $this->id;
    }

    /**
     * @param string $username
     */
    public function setUsername(string $username): void
    {
        $this->username = $username;
    }

    /**
     * @return string
     */
    public function getUsername(): ?string
    {
        return $this->username;
    }

    /**
     * @return null|string
     */
    public function getSalt(): ?string
    {
        // you *may* need a real salt depending on your encoder
        // see section on salt below
        return null;
    }

    /**
     * @return string
     */
    public function getPassword(): ?string
    {
        return $this->password;
    }

    /**
     * @param string $password
     */
    public function setPassword(string $password)
    {
        $this->password = $password;
    }

    /**
     * @return array
     */
    public function getRoles(): array
    {
//        return $this->roles;
        return ['ROLE_USER', 'ROLE_API_USER'];
    }

    /**
     *
     */
    public function eraseCredentials()
    {
    }

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

    /**
     * @see Serializable::unserialize()
     *
     * @param $serialized
     */
    public function unserialize($serialized)
    {
        list ($this->id, $this->email) = unserialize($serialized, array('allowed_classes' => false));
    }

    /**
     * @return string
     */
    public function getEmail(): ?string
    {
        return $this->email;
    }

    /**
     * @param string $email
     */
    public function setEmail(string $email): void
    {
        $this->email = $email;
    }

    /**
     * @return DateTime
     */
    public function getCreatedAt(): DateTime
    {
        return $this->createdAt;
    }

    /**
     * @ORM\PrePersist
     *
     * @throws Exception
     */
    public function setCreatedAt(): void
    {
        $this->createdAt = new DateTime();
    }

    /**
     * @return DateTime
     */
    public function getUpdatedAt(): DateTime
    {
        return $this->updatedAt;
    }

    /**
     * @ORM\PreUpdate
     *
     * @throws Exception
     */
    public function setUpdatedAt(): void
    {
        $this->updatedAt = new DateTime();
    }

    /**
     * @return DateTime
     */
    public function getActiveTo(): DateTime
    {
        return $this->activeTo;
    }

    /**
     * @param DateTime $activeTo
     */
    public function setActiveTo(DateTime $activeTo): void
    {
        $this->activeTo = $activeTo;
    }

    /**
     * @return string
     */
    public function getReferralCode(): string
    {
        return $this->referralCode;
    }

    /**
     * @param string $referralCode
     */
    public function setReferralCode(string $referralCode): void
    {
        $this->referralCode = $referralCode;
    }

    /**
     * @return string|null
     */
    public function getReferredByCode():? string
    {
        return $this->referredByCode;
    }

    /**
     * @param string|null $referredByCode
     */
    public function setReferredByCode(?string $referredByCode): void
    {
        $this->referredByCode = $referredByCode;
    }

    /**
     * @return string|null
     */
    public function getFirstName(): ?string
    {
        return $this->firstName;
    }

    /**
     * @param string|null $firstName
     */
    public function setFirstName(?string $firstName): void
    {
        $this->firstName = $firstName;
    }

    /**
     * @return string|null
     */
    public function getLastName(): ?string
    {
        return $this->lastName;
    }

    /**
     * @param string|null $lastName
     */
    public function setLastName(?string $lastName): void
    {
        $this->lastName = $lastName;
    }

    /**
     * @param array $roles
     */
    public function setRoles(array $roles): void
    {
        $this->roles = $roles;
    }

    /**
     * The equality comparison should neither be done by referential equality
     * nor by comparing identities (i.e. getId() === getId()).
     *
     * However, you do not need to compare every attribute, but only those that
     * are relevant for assessing whether re-authentication is required.
     *
     * @param UserInterface $user
     *
     * @return bool
     */
    public function isEqualTo(UserInterface $user)
    {
        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }
}

и security.yaml

    encoders:
        App\Entity\User\User:
            algorithm: auto

    providers:
        user_provider:
            entity:
                class: App\Entity\User\User
                property: username
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            http_basic: ~
            anonymous: true

#            logout_on_user_change: true
            provider: user_provider
            form_login:
                login_path: app_user_login
                check_path: app_user_login
                default_target_path: app_user_dashboard
                csrf_token_generator: security.csrf.token_manager
            logout:
                path:   /app/logout
                target: /app/login

            # activate different ways to authenticate

            # http_basic: true
            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: true
            # https://symfony.com/doc/current/security/form_login_setup.html

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/app/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/app/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/app, roles: IS_AUTHENTICATED_FULLY }

У меня есть красный пост: Токен был деаутентифицирован после попытки его обновить , и это решение не работает для меня. Есть идеи?

1 Ответ

1 голос
/ 25 июля 2019

У вас есть 2 варианта здесь:

  1. Сделайте ваш брандмауэр не имеющим состояния или
  2. обновить вашу сериализацию в вас User

Я имею в виду https://symfony.com/doc/current/security/user_provider.html#understanding-how-users-are-refreshed-from-the-session кстати, у меня была такая же проблема.

Первое решение:

firewalls:
    # ...

    main:
        http_basic: ~
        anonymous: true
        stateless: true

Это должно заставить Symfony игнорировать вашу сериализацию и просто перезагрузить всю сущность из базы данных.

Второе решение:

class User implements UserInterface, Serializable, EquatableInterface
{
    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->password,
            $this->email,
            $this->username,
            $this->activeTo,
        ));
    }

    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->password,
            $this->email,
            $this->username,
            $this->activeTo,
        ) = unserialize($serialized, array('allowed_classes' => false));
    }
}

Вы должны хранить любую информацию, которая может понадобиться Symfony в любом из ваших user_checker классов (или классов по умолчанию).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...