Symfony 4.4安全在登录后获得具有关联实体数据的用户



我使用Symfony 4.4的安全包。

我"User"实体与"信息"相关。

当我登录时,我想要有"Info"无需额外查询的数据

,例如在我的控制器(登录后)

当我使用$this->getUser();

时我

AppEntityUserUser {#1705 ▼
-id: 1
-email: "email@email.com"
-roles: array:1 [▶]
-password: "password"
-info: Proxies__CG__AppEntityUserInfo {#1716 ▼
+__isInitialized__: false
-id: 1
-firstname: null
-lastname: null
}
}

预期的结果

AppEntityUserUser {#1705 ▼
-id: 1
-email: "email@email.com"
-roles: array:1 [▶]
-password: "password"
-info: Proxies__CG__AppEntityUserInfo {#1716 ▼
+__isInitialized__: true
-id: 1
-firstname: "Firstname"
-lastname: "Lastname"
}
}

在我的守护下

在我的警卫的getUser方法中,我使用UserRepository通过电子邮件找到我的用户。

// AppSecurityAppCustomAuthenticator

public function getUser($credentials, UserProviderInterface $userProvider)
{
// Load / create our user however you need.
// You can do this by calling the user provider, or with custom logic here.
$user = $this->userRepository->findUserByEmail($credentials['email']);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('User not found');
}
return $user;
}
// AppRepositoryUserUserRepository
public function findUserByEmail(string $email): ?User
{
return $this->createQueryBuilder('user')
->addSelect('user_info')
->leftJoin('user.info', 'user_info')
->andWhere('user.email = :email')
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult()
;
}

但是我在登录后失去了实体Info数据。

登录后如何保存我的关系实体数据?

我发现这是一个非常好的问题,因为初学者经常遇到这个问题。自定义提供程序和getUser()方法之间的链接并不总是很明显。
通常情况下,用户并不是一个人在应用程序中,他带来了一个地址,一个团队,一个大小,一个颜色,一个包的信息,这是很有用的,随时随地,而无需额外的请求。

此链接适用于Symfony 4.xhttps://symfony.com/doc/4.0/security/custom_provider.html

这个链接对Synfony 5很有用。x
https://symfony.com/doc/current/security/user_provider.html using-a-custom-query-to-load-the-user

我遇到过同样的问题,如果有人总是寻找一个简单的解决方案。

让你的仓库实现UserProviderInterface,添加3个所需的方法(loadUserByUsername,refreshUser&supportsClass),修改loadUserByUsername方法加入wanted Doctrine关系并修改安全性。使用您的UserRepository作为自定义提供程序。

# src/Repository/UserRepository.php
<?php
namespace AppRepository;
use AppEntityUser as UserEntity;
use DoctrineBundleDoctrineBundleRepositoryServiceEntityRepository;
use DoctrinePersistenceManagerRegistry;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use SymfonyComponentSecurityCoreUserPasswordUpgraderInterface;
use SymfonyComponentSecurityCoreUserUser;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
/**
* @method null|UserEntity find($id, $lockMode = null, $lockVersion = null)
* @method null|UserEntity findOneBy(array $criteria, array $orderBy = null)
* @method UserEntity[]    findAll()
* @method UserEntity[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface, UserProviderInterface
{
/**
* UserRepository constructor.
*/
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, UserEntity::class);
}
public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
$user->setPassword($newEncodedPassword);
$this->_em->persist($user);
$this->_em->flush();
}
public function loadUserByUsername($username)
{
return $this->createQueryBuilder('u')
->select('u, i')
->leftJoin('u.info', 'i')
->where('u.username = :username')
->setParameter('username', $username)
->getQuery()
->getOneOrNullResult();
}
public function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return AppEntityUser::class === $class;
}
}
# config/packages/security.yaml
security:
encoders:
# ...
providers:
app_user_provider:
id: AppRepositoryUserRepository
firewalls:
# ...
access_control:
# ...

最新更新