You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 3.4 EventSubscriber中API鉴权失败如何返回响应并终止请求

解决方案

方案1:保持在KernelEvents::CONTROLLER事件中实现(适配你现有判断控制器接口的逻辑)

Symfony 3.4的FilterControllerEvent没有直接设置响应的方法,但你可以通过覆盖控制器的方式终止原有控制器执行,直接返回响应:

  • 校验失败时,创建你需要返回的响应实例(通常API场景用JsonResponse)
  • 调用$event->setController()传入一个直接返回响应的闭包,原有控制器逻辑就不会被触发

完整修改后的代码

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Doctrine\ORM\EntityManager;

class TokenSubscriber implements EventSubscriberInterface
{
    private $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function onKernelController(FilterControllerEvent $event)
    {
        // 跳过子请求,只校验主请求
        if (!$event->isMasterRequest()) {
            return;
        }
        
        $controller = $event->getController();

        if ($controller[0] instanceof TokenAuthenticatedController) {
            $apiKeyObj = $this->em->getRepository('AppBundle:ApiKey')->findOneBy(['enabled' => true, 'name' => 'apikey']);
            // 额外判断配置是否存在,避免调用空对象方法报错
            if (!$apiKeyObj) {
                $response = new JsonResponse(['code' => 401, 'message' => '服务端授权配置错误'], 401);
                $event->setController(function () use ($response) {
                    return $response;
                });
                return;
            }
            
            $apiKey = $apiKeyObj->getApiKey();
            $token = $event->getRequest()->headers->get('x-auth-token');
            if ($token !== $apiKey) {
                // 直接返回401响应
                $response = new JsonResponse(['code' => 401, 'message' => '无效的授权令牌'], 401);
                $event->setController(function () use ($response) {
                    return $response;
                });
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::CONTROLLER => 'onKernelController',
        ];
    }
}

方案2:改用KernelEvents::REQUEST事件实现(更适合全局授权校验)

如果你的授权校验不需要依赖控制器实例判断,可以把监听事件换成更早的KernelEvents::REQUEST,对应事件类GetResponseEvent自带setResponse方法,调用后会直接终止后续请求流程返回响应:

// 订阅事件改为
public static function getSubscribedEvents()
{
    return [
        KernelEvents::REQUEST => 'onKernelRequest',
    ];
}

// 校验方法修改为
public function onKernelRequest(GetResponseEvent $event)
{
    if (!$event->isMasterRequest()) {
        return;
    }
    // 你的校验逻辑
    if (校验失败) {
        $event->setResponse(new JsonResponse(['message' => '未授权'], 401));
    }
}

注意:两种方案都默认加了主请求判断,避免子请求(如twig里的render方法调用)被误拦截。

内容的提问来源于stack exchange,提问作者a_fgr3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 04:06:04