身份验证问题$user必须是用户界面的实例



我正在使用Symfony 4.4,并且在用户身份验证方面遇到了一个奇怪的问题。不幸的是,我自己无法重现该问题,但我可以在日志中看到它发生在我的少数用户身上。出现以下错误消息:

$user必须是 UserInterface 的实例、实现 __toString 方法的对象或基元字符串

堆栈跟踪:

{
"class": "InvalidArgumentException",
"message": "$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string.",
"code": 0,
"file": "/var/www/vendor/symfony/security/Core/Authentication/Token/AbstractToken.php:95",
"trace": [
"/var/www/vendor/symfony/security/Http/Firewall/ContextListener.php:224",
"/var/www/vendor/symfony/security/Http/Firewall/ContextListener.php:140",
"/var/www/vendor/symfony/security/Http/Firewall/AbstractListener.php:27",
"/var/www/vendor/symfony/security/Http/Firewall.php:139",
"/var/www/vendor/symfony/security/Http/Firewall.php:129",
"/var/www/vendor/symfony/security/Http/Firewall.php:97",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:304",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:264",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:239",
"/var/www/vendor/symfony/event-dispatcher/EventDispatcher.php:73",
"/var/www/vendor/symfony/http-kernel/HttpKernel.php:122",
"/var/www/vendor/symfony/http-kernel/HttpKernel.php:68",
"/var/www/vendor/symfony/http-kernel/Kernel.php:201",
"/var/www/public/index.php:34"
]
}

我怀疑令牌可能无法续订,消息主要出现在内部区域。有时它也出现在首次访问网站时,用户可能尚未登录。

我的防火墙如下所示:

firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
username_parameter: login[username]
password_parameter: login[password]
csrf_token_generator: security.csrf.token_manager
json_login:
check_path: json_login_check
provider: database
logout:
path: /logout
target: /
guard:
provider: open_id
authenticators:
- AppPathToOpenIdGuard

login_check是默认登录操作,并通过 xhrjson_login_check登录操作。此外,还有两个用户提供程序,默认一个(数据库(,另一个用于开放 id (open_id(。

提供程序如下所示:

providers:
database:
entity:
class: AppEntityUser
property: email
open_id:
id: AppPathToProvider

用户实体(简体(:

class User implements Serializable, UserInterface, EncoderAwareInterface
{
public function __toString(): string
{
return $this->getEmail();
}
public function __construct()
{
$this->salt = base_convert(sha1(uniqid(''.mt_rand(), true)), 16, 36);
$this->setEnabled(false);
$this->roles[] = 'ROLE_USER';
}
public function eraseCredentials(): void
{
}
public function serialize(): string
{
return serialize(array(
$this->id,
$this->email,
$this->password,
$this->salt,
));
}
public function unserialize($serialized): void
{
list(
$this->id,
$this->email,
$this->password,
$this->salt
) = unserialize($serialized);
}
}

两个提供程序(数据库和open_id(使用相同的用户实体。

正如我很少说的那样,出现问题,在大多数情况下,一切正常。

你的对象必须实现an object implementing a __toString method所以你缺少其中的 toString 方法。 添加到此方法User

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

应该做。 作为参考,请始终检查原始类: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Model/User.php

编辑:由于您已经编辑了问题(通过向其添加字符串(。我可以说它的问题可能是getEmail可能仍然呈现一个null,这不是一个字符串。请将其更改为

return (string) $this->getEmail();

如果电子邮件null,则它不会属于"原始字符串"类别。 null 是不实现用户界面的对象。

我怀疑问题出现在生产环境中的某个地方,所以如果你有可能直接在服务器上更新代码,请像这样更新它:

Symfony\Component\Security\Core\Authentication\Token\AbstractToken:(vendor/symfony/security-core/Authentication/Token/AbstractToken.php(

94.        if (!($user instanceof UserInterface || (is_object($user) && method_exists($user, '__toString')) || is_string($user))) {
95.            throw new InvalidArgumentException('$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string. ' . get_class($user) . ' given.');
96.        }

找出你在setUser()中到底收到了什么.

我怀疑你在这里nullContextListener

222.                $refreshedUser = $provider->refreshUser($user);
223.                $newToken = clone $token;
224.                $newToken->setUser($refreshedUser);

如果是这种情况,那么您应该检查refreshUser()UserProvider的方法发生了什么。

实际上,这是我放置一些日志记录以检查正在发生的事情的第一个地方。

我现在能够找到并解决问题。更改用户组 (ROLES( 后,由于无法刷新会话用户,因此会发生错误。

为了允许在不注销用户或收到错误消息的情况下更改角色,必须在用户实体中集成单独的 isEqualTo(( 方法。请参阅:https://symfony.com/doc/current/security/user_provider.html#comparing-users-manually-with-equatableinterface

最新更新