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

Symfony EventSubscriber如何检测需身份验证路由并触发404页面

实现方案

以下针对Symfony框架场景实现,全程不需要修改原有控制器的鉴权注解,仅通过EventSubscriber完成检测和跳转逻辑。

前置配置

首先在.env文件中添加开关配置:

# 开启后所有要求IS_AUTHENTICATED_FULLY的路由直接返回404
AUTH_REDIRECT_TO_404=true

在config/services.yaml中绑定该参数为服务参数:

parameters:
    app.auth_redirect_to_404: '%env(bool:AUTH_REDIRECT_TO_404)%'

编写EventSubscriber

<?php

namespace App\EventSubscriber;

use Doctrine\Common\Annotations\Reader;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Annotation\IsGranted;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class AuthRouteHideSubscriber implements EventSubscriberInterface
{
    public function __construct(
        private Reader $annotationReader,
        private ParameterBagInterface $parameterBag
    ){}

    public static function getSubscribedEvents(): array
    {
        // 优先级高于安全组件的鉴权监听,提前拦截
        return [
            KernelEvents::REQUEST => ['onKernelRequest', 10],
        ];
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        // 仅处理主请求
        if (!$event->isMainRequest()) {
            return;
        }

        // 开关未开启直接跳过
        if (!$this->parameterBag->get('app.auth_redirect_to_404')) {
            return;
        }

        $request = $event->getRequest();
        $controller = $request->attributes->get('_controller');

        // 解析控制器类和方法名
        if (is_string($controller) && str_contains($controller, '::')) {
            [$controllerClass, $methodName] = explode('::', $controller, 2);
        } elseif (is_array($controller)) {
            [$controllerClass, $methodName] = $controller;
        } else {
            return;
        }

        $needAuth = false;
        $reflectionClass = new \ReflectionClass($controllerClass);

        // 检测类级别@IsGranted注解
        /** @var IsGranted[] $classGrants */
        $classGrants = $this->annotationReader->getClassAnnotations($reflectionClass, IsGranted::class);
        foreach ($classGrants as $grant) {
            if ($grant->attributes === 'IS_AUTHENTICATED_FULLY') {
                $needAuth = true;
                break;
            }
        }

        // 类没有配置的话检测方法级别注解
        if (!$needAuth && $reflectionClass->hasMethod($methodName)) {
            $reflectionMethod = $reflectionClass->getMethod($methodName);
            /** @var IsGranted[] $methodGrants */
            $methodGrants = $this->annotationReader->getMethodAnnotations($reflectionMethod, IsGranted::class);
            foreach ($methodGrants as $grant) {
                if ($grant->attributes === 'IS_AUTHENTICATED_FULLY') {
                    $needAuth = true;
                    break;
                }
            }
        }

        // 符合条件返回404
        if ($needAuth) {
            throw new NotFoundHttpException();
        }
    }
}

注意事项

  • 如果你使用的是Symfony 6+的PHP属性而非注解,把Doctrine\Common\Annotations\Reader替换为Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface,对应修改读取属性的逻辑即可
  • 如果你在security.yaml中配置了access_control规则,需要额外注入Symfony\Component\Security\Http\AccessMapInterface,匹配当前请求的路径是否属于要求IS_AUTHENTICATED_FULLY的规则
  • 上述代码抛出NotFoundHttpException后,Symfony会自动渲染项目配置的404页面,和真实不存在的路由返回效果完全一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:00:00