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
相关产品推荐
相关产品推荐

