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

Symfony 4如何实现Twig中路由访问权限校验函数?

Symfony 4:在Twig中根据路由权限控制菜单显示

你提到的需求很常见——在构建动态菜单时只显示当前用户有权访问的路由。Symfony本身没有直接提供can_access_route这类内置Twig函数,但我们可以通过两种方式实现:一种是利用现有组件直接在Twig中编写逻辑,另一种是自定义一个更简洁的Twig函数,完全符合你期望的用法。


方式一:无需自定义代码,直接用Twig内置服务实现

如果你不想额外写PHP代码,可以直接在Twig模板中结合app.router(路由服务)和app.security(权限校验服务)来实现:

{% for route_name in ["cat_list","cat_map","cat_trips"] %}
    {# 获取路由定义 #}
    {% set route = app.router.getRouteCollection().get(route_name) %}
    {% if route is not empty %}
        {# 获取路由的安全规则(来自@Security注解) #}
        {% set security_rule = route.getOption('_security') %}
        {# 如果没有安全规则,默认允许访问;否则校验权限 #}
        {% if security_rule is empty or app.security.isGranted(security_rule) %}
            <a href="{{ path(route_name) }}">{{ route_name|trans }}</a>
        {% endif %}
    {% endif %}
{% endfor %}

注意点:

  • _security是Symfony自动为带有@Security注解的路由添加的选项,里面存储的就是你写的权限表达式(比如is_granted('ROLE_XYZ'))。
  • 生产环境下路由集合是缓存的,所以这个操作的性能不会有问题。
  • 如果你是通过YAML/XML配置路由权限(而不是注解),只要配置了_security选项,这个逻辑同样生效。

方式二:自定义Twig函数(推荐,更简洁)

如果希望模板代码更干净,像你期望的is_route_granted(route_name)那样调用,可以自定义一个Twig扩展函数:

1. 创建Twig扩展类

在src/Twig/目录下新建SecurityRouteExtension.php:

<?php

namespace App\Twig;

use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Routing\RouterInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class SecurityRouteExtension extends AbstractExtension
{
    private $authorizationChecker;
    private $router;

    public function __construct(AuthorizationCheckerInterface $authorizationChecker, RouterInterface $router)
    {
        $this->authorizationChecker = $authorizationChecker;
        $this->router = $router;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('is_route_granted', [$this, 'isRouteGranted']),
        ];
    }

    public function isRouteGranted(string $routeName): bool
    {
        // 获取路由定义
        $route = $this->router->getRouteCollection()->get($routeName);
        if (!$route) {
            return false;
        }

        // 获取路由的安全规则
        $securityExpression = $route->getOption('_security');
        if (!$securityExpression) {
            // 无安全限制的路由默认允许访问
            return true;
        }

        try {
            // 校验权限
            return $this->authorizationChecker->isGranted($securityExpression);
        } catch (\Exception $e) {
            // 处理表达式解析错误(比如表达式无效)
            return false;
        }
    }
}

2. 自动注册服务

Symfony 4会自动扫描src/目录下的类并注册为服务,所以你不需要额外配置,这个扩展会自动生效。

3. 在Twig中使用

现在你可以像期望的那样编写模板代码了:

{% for route_name in ["cat_list","cat_map","cat_trips"] %}
    {% if is_route_granted(route_name) %}
        <a href="{{ path(route_name) }}">{{ route_name|trans }}</a>
    {% endif %}
{% endfor %}

额外小修正

顺便提一下你代码里的两个小问题:

  • @Security注解少了闭合括号,正确写法是:@Security("is_granted('ROLE_XYZ')")
  • Twig循环数组里多了一个多余的逗号,应该改成:["cat_list","cat_map","cat_trips"]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:51:46