【问题标题】:Symfony 4 Validator - Auto logout if invalidSymfony 4 Validator - 如果无效则自动注销
【发布时间】:2018-11-03 11:55:38
【问题描述】:

我想用 Symfony Validator 验证我的用户对象 ($user) 并在表单输入数据有效/无效时返回 JsonResponse ($response)。 但是我有一个问题,当无法验证数据时我会自动注销。我必须再次登录,当某些数据无效时,这不是我所期望的行为。我找到了一种解决方法(见下面的 cmets),但这不是很令人满意:/

这是我的控制器的方法:

 /**
 * Update user profile data
 *
 * @Route("/api/users/updateprofile")
 * @Security("is_granted('USERS_LIST')")
 */

public function apiProfileUpdate(ValidatorInterface $validator, FlashMessageBuilder $flashMessageBuilder)
{
    $request = Request::createFromGlobals();
    // Prepare Response
    $response = new JsonResponse();
    $response->setData([]);
    /** @var User $user */
    $user = $this->getUser();
    $oldName = $user->getName();
    $oldEmail = $user->getEmail();

    $user->setName($request->request->get('name'));
    $user->setEmail($request->request->get('email'));

    $errors = $validator->validate($user);
    if (count($errors) > 0) { // if this -> auto logout
        $user->setName($oldName); // if I set the both attributes back to the old value
        $user->setEmail($oldEmail); // then I don't get logged out automatically but this is just a workaround and not satisfying
        $entityManager = $this->getDoctrine()->getManager(); // forgot to remove this
        $entityManager->persist($user); // and this line, this is actually deleted in the real code

        foreach ($errors as $error) {
            $errorMessage = $error->getMessage();
            $errorField = $error->getPropertyPath();
            $flashMessageBuilder->addErrorMessage($errorMessage, $errorField);
        };

        return $response;
    }

    $entityManager = $this->getDoctrine()->getManager();
    $entityManager->persist($user);
    $entityManager->flush();

    $flashMessageBuilder->addSuccessMessage("Success!");
    return $response;
}

对不起,我的英语不好,提前谢谢你!

【问题讨论】:

    标签: php symfony validation


    【解决方案1】:

    即使验证中出现错误,您也会保留用户对象,这可能会导致注销问题。

    仅在没有验证错误的情况下尝试更新:

    public function apiProfileUpdate(ValidatorInterface $validator, FlashMessageBuilder $flashMessageBuilder)
    {
        $request = Request::createFromGlobals();
    
        // Prepare Response
        $response = new JsonResponse();
        $response->setData([]);
    
        /** @var User $user */
        $user = $this->getUser();
    
        $user->setName($request->request->get('name'));
        $user->setEmail($request->request->get('email'));
    
        $errors = $validator->validate($user);
        if (count($errors) == 0) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($user);
            $entityManager->flush();
    
            $flashMessageBuilder->addSuccessMessage("Success!");
            return $response;
        }
    
        foreach ($errors as $error) {
            $errorMessage = $error->getMessage();
            $errorField = $error->getPropertyPath();
            $flashMessageBuilder->addErrorMessage($errorMessage, $errorField);
        };
    
        return $response;
    }
    

    但我认为您不应该将 API 调用和利用 FlashMessages 的经典表单方法混为一谈,而应返回正确的 JSON 结果。

    因此考虑相应地更改代码:

    public function apiProfileUpdate(ValidatorInterface $validator, FlashMessageBuilder $flashMessageBuilder)
    {
        $request = Request::createFromGlobals();
    
        /** @var User $user */
        $user = $this->getUser();
    
        $user->setName($request->request->get('name'));
        $user->setEmail($request->request->get('email'));
    
        $errors = $validator->validate($user);
        if (count($errors) == 0) {
            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($user);
            $entityManager->flush();
    
            return new JsonResponse(['success' => true]);
        }
    
        $data = [];
        foreach ($errors as $error) {
            $data[$error->getPropertyPath()] = $error->getMessage();
        };
    
        return new JsonResponse(['success' => false, 'errors' => $data], 400);
    }
    

    现在您的调用代码可以处理 200 结果(成功)和状态码为 400 的错误情况,并显示结果正文中 errors 部分中所有失败字段的错误消息。

    【讨论】:

    • 对不起,我忘了删除持久化,我只是把它放在那里是为了看看这是否可以防止注销问题,但它没有。 Flash 消息将在 JsonResponse 中自动返回(我创建了一个事件监听器)。
    • 好的,这种情况下请检查你是否开启了logout-on-user-change,见symfony.com/doc/current/reference/configuration/… 或者你遇到了那个bug:github.com/symfony/symfony/pull/28072
    • 谢谢 - 我已将 logout_on_user_change 设置为 false 现在这解决了问题。但是 Symfony 表示不推荐将其设置为 false - 我应该担心安全性吗?
    • 我认为它与您的 UserProvider 或防火墙设置有关。在我的应用程序(使用 Symfony 4.1.6)中,我在更改当前用户数据(用户名/电子邮件)时不会退出。我没有 logout_on_user_change,所以默认情况下它是真的。这就是为什么我最初认为这与你的坚持有关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 2020-03-02
    • 2023-02-20
    • 2019-12-03
    • 2014-02-13
    • 2013-08-02
    • 2018-05-24
    相关资源
    最近更新 更多