簡體   English   中英

Symfony 令牌是訂閱者中的 null

[英]Symfony token is null in Subscriber

我為需要訪問當前登錄用戶的 prePersist 和 preFlush 事件創建了一個偵聽器:

<?php

namespace App\EventListener;

use App\Entity\AbstractEntity;
use App\Entity\User;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Events;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Exception;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use function is_object;

class DatabaseActivitySubscriber implements EventSubscriber
{
    /**
     * @var TokenInterface|null
     */
    private ?TokenInterface $token;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->token = $tokenStorage->getToken();
    }

    /**
     * @return array|string[]
     */
    public function getSubscribedEvents()
    {
        return [
            Events::prePersist,
            Events::preUpdate,
        ];
    }

    /**
     * Initialise le nom de l'utilisateur a l'origine de la création sous la forme "Nom Prénom (id)"
     *
     * @param LifecycleEventArgs $args
     * @throws Exception
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        if ($args->getObject() instanceof AbstractEntity) {
            $args->getObject()->setCreateUser($this->getUser()->getLastName() . ' ' . $this->getuser()->getLastName() . ' (' . $this->getuser()->getId() . ')');
        }
    }

    /**
     * @return string|\Stringable|UserInterface|null|User
     */
    private function getUser()
    {

        if (null === $token = $this->token) {
            return null;
        }

        if (!is_object($user = $token->getUser())) {
            // e.g. anonymous authentication
            return null;
        }

        return $user;
    }

    /**
     * @param LifecycleEventArgs $args
     */
    public function preUpdate(LifecycleEventArgs $args)
    {
        if ($args->getObject() instanceof AbstractEntity) {
            $args->getObject()->setUpdateUser($this->getuser()->getLastName() . ' ' . $this->getuser()->getLastName() . ' (' . $this->getuser()->getId() . ')');
        }
    }
}

但令牌始終是 null。

所以我對controller中存在的東西做了一些驗證:


    /**
     * @Route("/create", name="create")
     * @param Request $request
     * @param TrainingManager $trainingManager
     * @return Response
     */
    public function create(Request $request, TrainingManager $trainingManager)
    {
        $training = new Training();
        $form = $this->createForm(FormNameType::class, $training);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
                $user = $this->getUser();
                $trainingManager->save($training);
        }
        return $this->render('create.html.twig', ['form' => $form->createView(),]);
    }

並且用戶可以很好地使用 $this->getUser(); 緊隨其后的那一行,我的 dataBaseSubscriber 啟動,在構造函數中的令牌是 null。 實際上是同一個令牌。

我檢查了“security.token_storage”是否正確自動裝配,我還嘗試在 service.yml 中強制它

這讓我很困惑。 這兩個 UsageTrackingStorage 實例之間的唯一區別是一個在 controller 中使用,另一個在訂閱者中使用。 但它應該注入同一個實例......

訂閱者(例如您的訂閱者)很可能在請求生命周期的早期就已初始化。 也就是說,在將請求分解為所有身份驗證內容之前。

TokenStorage 是正確的,但是,在您的訂閱者被初始化的那一刻(閱讀:__construct 被調用)幾乎什么都不存在,除了__construct本身,但它仍然是空的(顯然)。 有/可以有 EventSubscribers 可以更改身份驗證過程,因此如果令牌已經存在,那將是荒謬的。 (實際上我相信 symfony 中的身份驗證是通過 EventListeners 完成的)。

因此,當此時調用 getToken getToken()時,它返回 null,因為它不包含任何令牌,但是,這些是稍后添加的。

解決方案非常簡單:只需存儲 TokenStorage - 而不是 (null) 令牌 - 稍后在您真正需要它並且其中實際上有令牌時調用“getToken”。 開銷幾乎可以忽略不計(緩存可能是可能的,但看不到充分的理由)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM