Symfony 3,填充令牌并刷新用户

php symfony hwioauthbundle symfony-3.3

920 观看

2回复

391 作者的声誉

有问题的资料库

我有一个带有电子邮件字段的实体用户表单:

->add('email', EmailType::class, [
                'constraints' => [
                    new NotBlank(),
                    new Email([
                        'checkMX' => true,
                    ])
                ],
                'required' => true
            ])

当我将电子邮件编辑为类似test@gmail.com1形式并提交表单时,它向我显示错误“此值不是有效的电子邮件地址”。没关系,但是在该symfony将错误的电子邮件填充到令牌中后,当我转到任何其他页面或只是重新加载页面时,我得到了:

警告安全性在所选的用户提供程序中找不到用户名。

我认为问题是:为什么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(),
            ]
        );
    }

UPD: 如果我在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());
}

但它似乎是肮脏的骇客。

谢谢。

作者: kRicha 的来源 发布者: 2017 年 6 月 8 日

回应 (2)


3

240 作者的声誉

您的用户令牌似乎已由表单更新,即使电子邮件约束条件停止了刷新。

您可以检查表单是否超出了isValid函数吗?您可以尝试使用事件侦听器或验证器来避免这种情况。

通过事件SUBMIT,您应该能够检查电子邮件的完整性,然后添加FormError以避免refreshUser。

作者: fireaxe 发布者: 13.06.2017 12:49

2

1964 作者的声誉

决定

这是一个棘手的问题,这要归功于存储库,它可以更轻松地找出问题所在。您正在将身份验证令牌中的用户对象绑定到该createForm()方法。之后

$form->handleRequest($request)

取消令牌用户对象已更新的电子邮件。

我首先想到要通过在实体中实现EquatableInterface.html来解决此问题,User但这没有用,因为被比较的对象已经设置了错误的电子邮件地址。

实现EquatableInterface接口也可能很有用,该接口定义了一种检查用户是否等于当前用户的方法。此接口需要isEqualTo()方法。)

比我想过要从数据库强制重新加载用户并重置安全令牌,但是在我看来,万一表单失败,只要从数据库中刷新当前用户对象就足够了:

$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()]);
}

替代解决方案

Symfony存储库中问题导致了有关避免表单中的实体 取消安全性用户的耦合的一些有价值的输入,这为解决问题提供了更复杂的方法。

作者: lordrhodos 发布者: 17.06.2017 04:23
32x32