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