Symfony 3,填充令牌和刷新用户
Symfony 3, populating token and refreshing user
我有一个带有电子邮件字段的实体用户表单:
->add('email', EmailType::class, [
'constraints' => [
new NotBlank(),
new Email([
'checkMX' => true,
])
],
'required' => true
])
当我将电子邮件编辑为 test@gmail.com1
之类的内容并提交表单时,它显示错误 "This value is not a valid email address." 没关系,但在那之后 symfony 填充错误将电子邮件发送到令牌中,当我转到任何其他页面或只是重新加载页面时,我得到这个:
WARNING security Username could not be found in the selected user
provider.
我认为问题是:为什么 symfony 将验证失败的错误电子邮件填充到令牌中,我该如何防止它?
控制器:
public function meSettingsAction(Request $request)
{
$user = $this->getUser();
$userUnSubscribed = $this->getDoctrine()->getRepository('AppBundle:UserUnsubs')->findOneBy(
[
'email' => $user->getEmail(),
]
);
$form = $this->createForm(UserSettingsType::class, $user);
$form->get('subscribed')->setData(!(bool)$userUnSubscribed);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/**
* @var $user User
*/
$user = $form->getData();
/** @var UploadedFile $avatar */
$avatar = $request->files->get('user_settings')['photo'];
$em = $this->getDoctrine()->getManager();
if ($avatar) {
$avatar_content = file_get_contents($avatar->getRealPath());
$avatarName = uniqid().'.jpg';
$oldAvatar = $user->getPhoto();
$user
->setState(User::PHOTO_STATE_UNCHECKED)
->setPhoto($avatarName);
$gearmanClient = $this->get('gearman.client');
$gearmanClient->doBackgroundDependsOnEnv(
'avatar_content_upload',
serialize(['content' => $avatar_content, 'avatarName' => $avatarName, 'oldAvatar' => $oldAvatar])
);
}
$subscribed = $form->get('subscribed')->getData();
if ((bool)$userUnSubscribed && $subscribed) {
$em->remove($userUnSubscribed);
} elseif (!(bool)$userUnSubscribed && !$subscribed) {
$userUnSubscribed = new UserUnsubs();
$userUnSubscribed->setEmail($form->get('email')->getData())->setTs(time());
$em->persist($userUnSubscribed);
}
$user->setLastTs(time());
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->get('user.manager')->refresh($user);
return $this->redirectToRoute('me');
}
return $this->render(
':user:settings.html.twig',
[
'form' => $form->createView(),
]
);
}
更新:
如果我更改 OAuthProvider:
它工作正常
/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getName());
}
至:
/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->userManager($user->getId());
}
但这似乎是肮脏的 hack。
谢谢。
您的用户令牌似乎已被表单更新,即使电子邮件约束停止刷新。
你能检查一下你的表单是否通过了 isValid 函数吗?
您也许可以尝试使用事件侦听器或验证器来避免它。
使用事件 SUBMIT,您应该能够检查电子邮件完整性,然后添加 FormError 以避免 refreshUser。
这是一个棘手的问题,感谢存储库,它更容易隔离问题。您将用户对象从身份验证令牌绑定到 createForm()
方法。
之后
$form->handleRequest($request)
关闭令牌用户对象已更新的电子邮件。
我首先想到通过在 User
实体中实现 EquatableInterface.html 来解决这个问题,但这没有用,因为比较的对象已经设置了错误的电子邮件地址。
It may also be useful to implement the EquatableInterface interface, which defines a method to check if the user is equal to the current user. This interface requires an isEqualTo() method.)
比起我考虑强制从数据库重新加载用户并重置安全令牌,但在我的脑海中,可能只从数据库刷新当前用户对象就足够了,以防万一表格失败:
$this->get('doctrine')->getManager()->refresh($this->getUser());`
在您的控制器中,这将解决您的问题。
/**
* @Route("/edit_me", name="edit")
* @Security("has_role('ROLE_USER')")
*/
public function editMyselfAction(Request $request) {
$form = $this->createForm(User::class, $this->getUser());
if ($request->isMethod(Request::METHOD_POST)) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
} else {
$this->get('doctrine')->getManager()->refresh($this->getUser());
}
}
return $this->render(':security:edit.html.twig',['form' => $form->createView()]);
}
备选方案
issue at the Symfony repository resulted in some valuable input about Avoiding Entities in Forms 和
Decoupling Your Security User 它提供了一种更复杂的方法来解决您的问题。
我有一个带有电子邮件字段的实体用户表单:
->add('email', EmailType::class, [
'constraints' => [
new NotBlank(),
new Email([
'checkMX' => true,
])
],
'required' => true
])
当我将电子邮件编辑为 test@gmail.com1
之类的内容并提交表单时,它显示错误 "This value is not a valid email address." 没关系,但在那之后 symfony 填充错误将电子邮件发送到令牌中,当我转到任何其他页面或只是重新加载页面时,我得到这个:
WARNING security Username could not be found in the selected user provider.
我认为问题是:为什么 symfony 将验证失败的错误电子邮件填充到令牌中,我该如何防止它?
控制器:
public function meSettingsAction(Request $request)
{
$user = $this->getUser();
$userUnSubscribed = $this->getDoctrine()->getRepository('AppBundle:UserUnsubs')->findOneBy(
[
'email' => $user->getEmail(),
]
);
$form = $this->createForm(UserSettingsType::class, $user);
$form->get('subscribed')->setData(!(bool)$userUnSubscribed);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/**
* @var $user User
*/
$user = $form->getData();
/** @var UploadedFile $avatar */
$avatar = $request->files->get('user_settings')['photo'];
$em = $this->getDoctrine()->getManager();
if ($avatar) {
$avatar_content = file_get_contents($avatar->getRealPath());
$avatarName = uniqid().'.jpg';
$oldAvatar = $user->getPhoto();
$user
->setState(User::PHOTO_STATE_UNCHECKED)
->setPhoto($avatarName);
$gearmanClient = $this->get('gearman.client');
$gearmanClient->doBackgroundDependsOnEnv(
'avatar_content_upload',
serialize(['content' => $avatar_content, 'avatarName' => $avatarName, 'oldAvatar' => $oldAvatar])
);
}
$subscribed = $form->get('subscribed')->getData();
if ((bool)$userUnSubscribed && $subscribed) {
$em->remove($userUnSubscribed);
} elseif (!(bool)$userUnSubscribed && !$subscribed) {
$userUnSubscribed = new UserUnsubs();
$userUnSubscribed->setEmail($form->get('email')->getData())->setTs(time());
$em->persist($userUnSubscribed);
}
$user->setLastTs(time());
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->get('user.manager')->refresh($user);
return $this->redirectToRoute('me');
}
return $this->render(
':user:settings.html.twig',
[
'form' => $form->createView(),
]
);
}
更新: 如果我更改 OAuthProvider:
它工作正常/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getName());
}
至:
/**
* @param \Symfony\Component\Security\Core\User\UserInterface $user
*
* @return \Symfony\Component\Security\Core\User\UserInterface
*/
public function refreshUser(UserInterface $user)
{
return $this->userManager($user->getId());
}
但这似乎是肮脏的 hack。
谢谢。
您的用户令牌似乎已被表单更新,即使电子邮件约束停止刷新。
你能检查一下你的表单是否通过了 isValid 函数吗? 您也许可以尝试使用事件侦听器或验证器来避免它。
使用事件 SUBMIT,您应该能够检查电子邮件完整性,然后添加 FormError 以避免 refreshUser。
这是一个棘手的问题,感谢存储库,它更容易隔离问题。您将用户对象从身份验证令牌绑定到 createForm()
方法。
$form->handleRequest($request)
关闭令牌用户对象已更新的电子邮件。
我首先想到通过在 User
实体中实现 EquatableInterface.html 来解决这个问题,但这没有用,因为比较的对象已经设置了错误的电子邮件地址。
It may also be useful to implement the EquatableInterface interface, which defines a method to check if the user is equal to the current user. This interface requires an isEqualTo() method.)
比起我考虑强制从数据库重新加载用户并重置安全令牌,但在我的脑海中,可能只从数据库刷新当前用户对象就足够了,以防万一表格失败:
$this->get('doctrine')->getManager()->refresh($this->getUser());`
在您的控制器中,这将解决您的问题。
/**
* @Route("/edit_me", name="edit")
* @Security("has_role('ROLE_USER')")
*/
public function editMyselfAction(Request $request) {
$form = $this->createForm(User::class, $this->getUser());
if ($request->isMethod(Request::METHOD_POST)) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
} else {
$this->get('doctrine')->getManager()->refresh($this->getUser());
}
}
return $this->render(':security:edit.html.twig',['form' => $form->createView()]);
}
备选方案
issue at the Symfony repository resulted in some valuable input about Avoiding Entities in Forms 和 Decoupling Your Security User 它提供了一种更复杂的方法来解决您的问题。