symfony教程之动态权限注入

Mario Sanchez

18 people read
Thumbnail

我们在进行symfony开发时,经常会为不同的用户取一个不同的角色名,但是这些角色都有一个基础的权限。

比如ROLE_SUPER_ADMIN和ROLE_MAIN_ADMIN都是管理员,他们都有ROLE_ADMIN的所有权限,这样在路由守卫时可以用ROLE_ADMIN来做为角色限制。

所以在symfony的security.yaml中我们会用role_hierarchy来定义角色权限:

    role_hierarchy:
        ROLE_SUPER_ADMIN: ROLE_ADMIN

但在现实开发中,我们可能会自定义添加修改角色,把角色写入数据库,由程序使用者来定义的话,肯定不能通过修改yaml文件来实现。所以我们希望能从系统中动态设置,那么这个时候怎么处理呢?

其实很简单:我们只需要装饰security.role_hierarchy服务即可,比如我这里仅仅简单的把所有添加的角色都具有ROLE_ADMIN的权限:

<?php

namespace App\Security;

use App\Repository\RolesRepository;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

#[AsDecorator('security.role_hierarchy')]
class DynamicRoleHierarchy implements RoleHierarchyInterface
{
    public function __construct(
        private RolesRepository $rolesRepository,
        private CacheInterface  $cache
    )
    {
    }

    public function getReachableRoleNames(array $roles): array
    {
        $reachableRoles = [];
        // 获取所有角色代码
        $allRoles = $this->getAllRoles();
        foreach ($roles as $role) {
            // 将用户本身拥有的角色添加到可达角色列表中
            $reachableRoles[] = $role;
            // 如果用户拥有的角色在数据库中存在,则添加 ROLE_ADMIN 权限
            if (in_array($role, $allRoles)) {
                $reachableRoles[] = 'ROLE_ADMIN';
            }
        }
        return array_unique($reachableRoles);
    }

    private function getAllRoles(): array
    {
        return $this->cache->get('all_roles', function (ItemInterface $item) {
            $item->expiresAfter(3600); // 缓存 1 小时
            // 获取所有角色代码
            $roles = $this->rolesRepository->findAll();
            $roleCodes = [];
            foreach ($roles as $role) {
                $roleCodes[] = $role->getCode();
            }
            return $roleCodes;
        });
    }
}

代码很简单,相信我不需要过多的解释。但是如果仅仅这样做的话,你会发现在使用

isGranted("ROLE_SUPER_ADMIN")

判断角色时会没有作用,所以这里需要我们在security.yaml中这样处理:

    role_hierarchy:
        ROLE_ADMIN: ROLE_ADMIN

这里的ROLE_ADMIN你可以试一试其它的是否可行,我这里仅仅是把ADMIN这个最基本的角色放在这里而已,所有逻辑都可以生效。

About Me

我是一位精通 Symfony 框架和 API Platform 的开发者,擅长构建高效、可扩展的 Web 应用程序和 API。 此外,我还具备 PrestaShop 模块开发经验,能够为您的电商平台定制功能,满足特定业务需求。