繁体   English   中英

成功登录 Symfony 4 后用户仍然匿名

[英]User still Anonymous after successful login Symfony 4

所以我创建了一个传统的登录表单。 成功登录后,它重定向到我的仪表板,然后重定向回登录。 检查后,用户是匿名的,并通过身份验证。 我还能够将用户转储到我的自定义提供程序上。 我怀疑,Symfony 不会在会话中保存它。 为什么呢?

这是我到目前为止所做的:

安全.yml:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt
    providers:
        user_provider:
            id: App\Security\UserProvider
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            form_login:
                login_path: security_login
                check_path: security_login
                default_target_path: dashboard

            # activate different ways to authenticate

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

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

    access_control:
        - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, roles: ROLE_ADMIN }

    role_hierarchy:
        ROLE_SUPER_ADMIN:
            - ROLE_ALLOWED_TO_SWITCH
            - ROLE_ADMIN

框架.yml

framework:
    secret: '%env(APP_SECRET)%'
    #default_locale: en
    #csrf_protection: ~
    #http_method_override: true

    # Enables session support. Note that the session will ONLY be started if you read or write from it.
    # Remove or comment this section to explicitly disable session support.
    session:
        # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id
        handler_id: session.handler.native_file
        save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%'

    #esi: ~
    #fragments: ~
    php_errors:
        log: true

    cache:
        # Put the unique name of your app here: the prefix seed
        # is used to compute stable namespaces for cache keys.
        #prefix_seed: your_vendor_name/app_name

        # The app cache caches to the filesystem by default.
        # Other options include:

        # Redis
        #app: cache.adapter.redis
        #default_redis_provider: redis://localhost

        # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
        #app: cache.adapter.apcu

用户提供者

class UserProvider implements UserProviderInterface
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function loadUserByUsername($username)
    {   
        $user = $this->em->getRepository(User::class)->loadByUsername($username);

        if ($user) {
            return $user;
        }

        throw new UsernameNotFoundException(
            sprintf('Username "%s" does not exist.', $username)
        );
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(
                sprintf('Instances of "%s" are not supported.', get_class($user))
            );
        }

        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class)
    {
        return User::class === $class;
    }
}

用户

use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Entity()
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @UniqueEntity("email", message="Email is already taken.")
 * @UniqueEntity("username", message="Username is already taken.")
 */
class User implements AdvancedUserInterface, EquatableInterface, \Serializable
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="Username must not be blank.")
     */
    private $username;

    /**
     * @Assert\NotBlank(message="Password must not be blank.")
     */
    private $plainPassword;

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

    /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="Email must not be blank.")
     * @Assert\Email()
     */
    private $email;

   /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="First name must not be blank.")
     */
    private $firstName;

    /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="Last name must not be blank.")
     */
    private $lastName;

    /**
     * @ORM\Column(type="json_array")
     */
    private $roles;

    public function __construct()
    {
        $this->roles = [];
    }

    public function setFirstName(string $firstName)
    {
        $this->firstName = $firstName;

        return $this;
    }

    public function getFirstName(): ?string
    {
        return $this->firstName;
    }

    public function setLastName(string $lastName)
    {
        $this->lastName = $lastName;

        return $this;
    }

    public function getLastName(): ?string
    {
        return $this->lastName;
    }

    public function setUsername(string $username): User
    {
        $this->username = $username;

        return $this;
    }

    public function setEmail(string $email): User
    {
        $this->email = $email;

        return $this;
    }

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

    public function setPassword($password)
    {
        $this->password = $password;

        return $this->password;
    }

    public function setPlainPassword($plainPassword) : User
    {
        $this->plainPassword = $plainPassword;

        return $this;
    }

    public function getPlainPassword() : ?string
    {
        return $this->plainPassword;
    }

    public function setRoles(array $roles): User
    {
        $this->roles = $roles;

        return $this;
    }

    // Overriden Methods

    public function getPassword()
    {
        return $this->password;
    }

    public function getUsername()
    {
        return $this->username;
    }

    public function eraseCredentials()
    {

    }

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof WebserviceUser) {
            return false;
        }

        if ($this->password !== $user->getPassword()) {
            return false;
        }

        if ($this->salt !== $user->getSalt()) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }

    public function isAccountNonExpired()
    {
        return true;
    }

    public function isAccountNonLocked()
    {
        return true;
    }

    public function isCredentialsNonExpired()
    {
        return true;
    }

    public function isEnabled()
    {
        return true;
    }

    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->username,
            $this->password,
            $this->roles,
        ));
    }

    public function unserialize($serialized)
    {
        list (
            $this->id,
            $this->username,
            $this->password,
            $this->roles
        ) = unserialize($serialized);
    }

    public function getRoles()
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function getSalt()
    {
        return null;
    }
}

谢谢!

注意:我将 docker 与 Nginx 和 PHP-FPM 图像一起使用。

今天我自己也遇到了同样的问题,并且脸部也有了类似的时刻。 就我而言,事实证明我们并未序列化要在AdvancedUserInterface方法中使用的所有必需的User实体数据。

例如:

UserEntity

...

public function isEnabled ()
{
    return (0 < $this->status);
}

public function serialize ()
{
    return serialize(array(
        $this->id,
        $this->username,
        $this->password,
        // $this->status, <- this was missing and needed added
    ));
}

public function unserialize ($serialized)
{
    list (
        $this->id,
        $this->username,
        $this->password
        //, $this->status <-- this was missing and needed added

    ) = unserialize($serialized, array ("allowed_classes" => false));
}

...

因为我们没有使用$this->status属性来序列化该对象,所以使用未序列化的UserEntity时, isEnabled()方法失败。 添加属性并清除会话后,它又可以正常工作了。

这可能会对某人有所帮助,我在此上花了几个小时,并且遇到了类似的问题..确保用户序列化正确

造成很多痛苦的原因..

public function serialize()
{
    return serialize(array(
        $this->id, $this->username, $this->password, // see section on salt below
        // $this->salt,
    ));
}

public function unserialize($serialized)
{
    list ($this->id, $this->username, $this->password, // see section on salt below
        // $this->salt
        ) = unserialize($serialized, array('allowed_classes' => false));
}

固定

public function serialize()
{
    return serialize(array(
        $this->id, $this->username, $this->password, $this->salt,
    ));
}

public function unserialize($serialized)
{
    list ($this->id, $this->username, $this->password, $this->salt) 

        = unserialize($serialized, array('allowed_classes' => false));
}

用户创建...

        $user->setSalt(bin2hex(random_bytes(16)));

        $encoder = new MessageDigestPasswordEncoder('sha512', true, 5000);

        $encodedPassword = $encoder->encodePassword($password, $user->getSalt());

        $user->setPassword($encodedPassword);

在从 Symfony2 到 Symfony 5 的项目迁移过程中遇到了这个问题。所以,我做了什么:

将用户实体文件重命名为 User.php_

按照文档中的描述运行 php bin/console make:user

然后将来自生成实体的方法与现有实体进行比较。

另外,从 User 实体中删除了 \\Serializable 接口,因为我不需要它(如果您需要一个实体可序列化,只需正确实现它)

如果你从旧版本的 Symfony 迁移到 4/5 版本,最好用所有相关的东西(比如配置、登录和注册控制器)重新生成表单登录并重新实现它: https : //symfony.com /doc/current/security/form_login_setup.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM