TokenStorageInterface注入订阅者调用的服务后始终返回空问题咨询
问题原因
- 实例化时机错误:Symfony 的事件订阅者会在容器初始化阶段就完成实例化,你在
OverridesSubscriber的构造函数中直接调用RestaurantService::getRestaurantId()时,安全认证流程还未执行,TokenStorage中还没有写入登录用户的 Token,要么返回 null 要么返回未完成认证的 Token。 - 类型判断逻辑错误:
TokenStorageInterface::getToken()返回的是Symfony\Component\Security\Core\Authentication\Token\TokenInterface接口的实现对象,或者未认证时返回 null,永远不会直接返回User实例,需要调用 Token 对象的getUser()方法才能拿到关联的用户对象,所以原有的类型判断本身就不成立,必然永远返回 false。
解决方法
- 首先修正
RestaurantService中的用户判断逻辑:
public function getRestaurantId(): ?int { $token = $this->tokenStorage->getToken(); // 依次校验Token存在、已完成认证、用户类型符合要求 if (!$token || !$token->isAuthenticated() || !($user = $token->getUser()) instanceof User) { return null; // 未登录场景可根据业务需求返回默认值或抛出异常 } // 后续获取用户关联restaurantId的业务逻辑 }
- 调整事件订阅者的逻辑执行时机,不要在构造函数中执行业务逻辑,改为在对应事件的回调方法中调用:
class OverridesSubscriber implements EventSubscriberInterface { private RestaurantService $restaurantService; // 构造函数仅做依赖注入,不执行任何需要运行时上下文的业务逻辑 public function __construct(RestaurantService $restaurantService) { $this->restaurantService = $restaurantService; } // 在监听的事件回调方法中执行获取商户ID的逻辑 public function onTargetEvent(TargetEventClass $event) { $restaurantId = $this->restaurantService->getRestaurantId(); // 后续业务逻辑处理 } public static function getSubscribedEvents() { // 保留你原有事件配置,注意选择安全认证流程完成后才触发的事件 return [ TargetEventClass::class => 'onTargetEvent', ]; } }
- 额外注意:如果监听的是请求类事件,需要确保监听优先级低于安全防火墙的处理优先级,避免在认证流程完成前就执行逻辑。
内容的提问来源于stack exchange,提问作者Onur Aydeniz
相关产品推荐
相关产品推荐

