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

