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

如何检查登录用户是否拥有访问其他控制器的权限?

解决方案

要实现这个需求,你可以结合Symfony的注解解析器、权限校验组件和访问控制映射来完成,以下是具体实现步骤:

1. 解析控制器的IsGranted注解

使用Symfony的AnnotationReader读取目标控制器类(或__invoke方法)上的IsGranted注解,注意方法级注解优先级高于类级注解。

use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Security\Http\Annotation\IsGranted;

private function getControllerIsGrantedAnnotations(string $controllerClass): array
{
    $reader = new AnnotationReader();
    $reflectionClass = new \ReflectionClass($controllerClass);
    
    // 读取类级注解
    $classAnnotations = $reader->getClassAnnotations($reflectionClass);
    $isGrantedAnnotations = array_filter($classAnnotations, fn($anno) => $anno instanceof IsGranted);
    
    // 读取__invoke方法的注解(优先级更高)
    if ($reflectionClass->hasMethod('__invoke')) {
        $methodAnnotations = $reader->getMethodAnnotations($reflectionClass->getMethod('__invoke'));
        $methodIsGranted = array_filter($methodAnnotations, fn($anno) => $anno instanceof IsGranted);
        if (!empty($methodIsGranted)) {
            return $methodIsGranted;
        }
    }
    
    return $isGrantedAnnotations;
}

2. 校验注解中的权限/表达式

拿到IsGranted注解后,用AuthorizationCheckerInterface和ExpressionLanguage判断当前用户是否有权限,同时处理带实体主题的表达式。

use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

private function checkIsGrantedAnnotation(IsGranted $annotation, $subject, AuthorizationCheckerInterface $authorizationChecker): bool
{
    // 处理简单权限字符串
    if (!empty($annotation->attributes)) {
        foreach ($annotation->attributes as $attribute) {
            if (!$authorizationChecker->isGranted($attribute, $subject)) {
                return false;
            }
        }
        return true;
    }
    
    // 处理表达式
    if (!empty($annotation->expression)) {
        $expressionLanguage = new ExpressionLanguage();
        $variables = [
            'user' => $authorizationChecker->getUser(),
            'subject' => $subject,
            'security' => new Security($authorizationChecker),
        ];
        return $expressionLanguage->evaluate($annotation->expression, $variables);
    }
    
    return true;
}

3. 结合security.yaml中的访问控制规则

除了注解,还要检查security.yaml里的access_control约束,用AccessMapInterface匹配控制器对应的路由,判断用户是否符合规则。

use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;

private function checkAccessControl(string $controllerClass, AccessMapInterface $accessMap, AuthorizationCheckerInterface $authorizationChecker, RouterInterface $router): bool
{
    // 反向解析控制器对应的路由
    $targetRoute = null;
    foreach ($router->getRouteCollection()->all() as $routeName => $routeObj) {
        if ($routeObj->getDefault('_controller') === $controllerClass) {
            $targetRoute = $routeObj;
            break;
        }
    }
    
    if (!$targetRoute) {
        return true; // 无对应路由,跳过检查
    }
    
    // 模拟请求匹配AccessMap规则
    $request = Request::create($targetRoute->getPath());
    list($accessConfigs) = $accessMap->getPatterns($request);
    
    foreach ($accessConfigs as $accessConfig) {
        if (!$authorizationChecker->isGranted($accessConfig->getRoles(), $request)) {
            return false;
        }
    }
    
    return true;
}

4. 封装成统一的检查函数

整合以上逻辑,实现你需要的控制器权限批量检查功能:

use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\Routing\RouterInterface;

public function getAvailableActions(array $controllers, $subject): array
{
    $authorizationChecker = $this->container->get(AuthorizationCheckerInterface::class);
    $accessMap = $this->container->get(AccessMapInterface::class);
    $router = $this->container->get(RouterInterface::class);
    
    $result = [];
    foreach ($controllers as $actionName => $controllerClass) {
        // 检查注解权限
        $annotations = $this->getControllerIsGrantedAnnotations($controllerClass);
        $annotationAllowed = true;
        foreach ($annotations as $anno) {
            if (!$this->checkIsGrantedAnnotation($anno, $subject, $authorizationChecker)) {
                $annotationAllowed = false;
                break;
            }
        }
        
        // 检查access_control规则
        $accessControlAllowed = $this->checkAccessControl($controllerClass, $accessMap, $authorizationChecker, $router);
        
        $result[$actionName] = $annotationAllowed && $accessControlAllowed;
    }
    
    return $result;
}

注意事项

  • 确保已安装doctrine/annotations包:composer require doctrine/annotations
  • 表达式中的特殊变量可根据需求补充到$variables数组中
  • 若控制器对应多个路由,需遍历所有路由完成access_control检查
  • 可缓存注解解析结果,避免重复反射类影响性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:06:28