Symfony 6.4 - 模拟用户 - 无法使用参数访问路由

问题描述 投票:0回答:1

context: 我正在开发一个 Symfony 6.4 应用程序,其中父母可以有多个孩子,并以他们的名字与应用程序进行交互。所以我有一个父级(用户实体)链接到一个或多个子级(用户实体)。

我决定使用 Symfony 中包含的“模拟用户”功能: https://symfony.com/doc/current/security/impersonating_user.html

由于家长在注册时不需要为孩子注册电子邮件地址,因此我必须使用 ID 而不是用户名来更改用户。我使用自定义控制器、自定义投票器并配置第二个安全提供程序来完成此操作。

用户切换效果很好:我可以从父级切换到子级,再切换回父级等等。

但是,当我使用 Child 并尝试导航到带有参数(例如 ID)的路线时,它不起作用,并且收到以下错误消息:

An exception has been raised when rendering a template (“Some mandatory parameters are missing (”id“ ) to generate a URL for route ‘app_message_detail’.”).

当我检查生成的 HTML 代码时,ID 确实存在。
当我转储到控制器时,ID 就出现了。

当我检查调试工具栏时,我看到有 302 响应。

我已经检查参数是否已传递到控制器:好的
我已检查用户是否具有正确的角色:好的
我已经检查过该路线是否适用于父级:好的

文件:

config/packages/security.yaml

security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    providers:
        # used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email
        # Used to switch user feature
        app_switch_user:
            entity:
                class: App\Entity\User
                property: id
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_user_provider

            form_login:
                login_path: app_login
                check_path: app_login
                enable_csrf: true

            login_throttling:
                max_attempts: 3

            logout:
                path: app_logout

            user_checker: App\Security\UserChecker

            switch_user:
                {
                    role: ROLE_PARENT,
                    parameter: _switch_user,
                    provider: app_switch_user,
                }

src/controller/UserController.php

#[Route('/switch-user/{userId}', name: 'app_switch_user')]
#[IsGranted('ROLE_USER')]
public function switchUser($userId, AuthorizationCheckerInterface $authChecker): RedirectResponse
{
    $user = $this->userRepository->find($userId);

    if (!$user) {
        throw $this->createNotFoundException($this->translator->trans('error.user_not_found'));
    }

    if (!$authChecker->isGranted('SWITCH', $user)) {
        throw $this->createAccessDeniedException($this->translator->trans('error.access_denied'));
    }

    $this->addFlash('warning', $this->translator->trans('warning.user_switched', ['firstname' => $user->getFirstname(), 'lastname' => $user->getLastname()]));

    return $this->redirectToRoute('app_home', [
        '_switch_user' => $user->getId(),
    ]);
}

src/Security/Voter/SwitchUserVoter.php

namespace App\Security\Voter;

use App\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class SwitchUserVoter extends Voter
{
    protected function supports(string $attribute, mixed $subject): bool
    {
        return $attribute === 'SWITCH' && $subject instanceof User;
    }

    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }

        return $this->canSwitch($user, $subject);
    }

    private function canSwitch(User $parent, User $enfant)
    {
        return in_array($enfant, $parent->getChildren()->toArray());
    }
}

src/controller/MessageController.php

#[Route('/{messageId}', name: 'app_message_detail')]
#[IsGranted('ROLE_USER')]
public function detail($messageId): Response
{
    try {
        $message = $this->findMessage($messageId);

        // Mark message as read
        $messageStatus = $this->messageStatusRepository->findOneBy(['message' => $message, 'receiver' => $this->getUser()]);

        if ($messageStatus) {
            $messageStatus->setStatus(true);

            $this->entityManager->persist($messageStatus);
            $this->entityManager->flush();
        }

        return $this->render('message/detail.html.twig', [
            "message" => $message
        ]);
    } catch (Exception $e) {
        $this->addFlash('error', $e->getMessage());
        return $this->redirectToRoute('app_messages');
    }
}
symfony routes parameters impersonation switch-user
1个回答
0
投票

您的错误似乎出在模板中。也许您正在调用“path()”函数并缺少一些参数。可以分享一下你的页面代码吗?我的意思是你有错误的 TWIG 文件

© www.soinside.com 2019 - 2024. All rights reserved.