programarivm/easy-acl-bundle

在Symfony 5中使用的易于使用的访问控制列表(ACL)包。

安装: 22

依赖关系: 0

建议者: 0

安全: 0

星标: 7

关注者: 1

分支: 0

开放问题: 1

类型:symfony-bundle

0.9.07 2023-08-08 13:39 UTC

This package is not auto-updated.

Last update: 2024-09-23 18:43:14 UTC


README

在Symfony 5中使用的易于使用的访问控制列表(ACL)包。

安装

通过composer

$ composer require programarivm/easy-acl-bundle

配置

config/routes.yaml中配置您的应用程序路由。

# config/routes.yaml
api_post_create:
    path:       /api/posts
    controller: App\Controller\Post\CreateController::index
    methods:    POST

api_post_delete:
    path:       /api/posts/{id}
    controller: App\Controller\Post\DeleteController::index
    methods:    DELETE

api_post_edit:
    path:       /api/posts/{id}
    controller: App\Controller\Post\EditController::index
    methods:    PUT

设置权限,如下所示。

# config/packages/programarivm_easy_acl.yaml
programarivm_easy_acl:
  target: App\Entity\User
  permission:
    -
      role: Superadmin
      routes:
        - api_post_create
        - api_post_delete
        - api_post_edit
    -
      role: Admin
      routes:
        - api_post_create
        - api_post_edit
    -
      role: Basic
      routes:
        - api_post_create

更新您的config/services.yaml文件。

# config/services.yaml
services:
    Programarivm\EasyAclBundle\Command\SetupCommand:
        arguments:
            $projectDir: '%kernel.project_dir%'
        tags: ['console.command']

    Programarivm\EasyAclBundle\Repository\:
        resource: '../vendor/programarivm/easy-acl-bundle/src/Repository'
        autowire: true
        tags: ['doctrine.repository_service']

    Programarivm\EasyAclBundle\EventListener\IdentitySubscriber:
        tags: ['doctrine.event_subscriber']

别忘了更新您的数据库模式

php bin/console doctrine:schema:update --force

这将在您的数据库中创建四个空表

  • easy_acl_identity
  • easy_acl_permission
  • easy_acl_role
  • easy_acl_route

这些与实体密切相关

以及存储库

easy-acl:setup命令

命令行

php bin/console easy-acl:setup
This will reset the ACL. Are you sure to continue? (y) y

MySQL控制台

mysql> select * from easy_acl_identity;
Empty set (0.01 sec)

mysql> select * from easy_acl_permission;
+----+------------+-----------------+
| id | rolename   | routename       |
+----+------------+-----------------+
|  1 | Superadmin | api_post_create |
|  2 | Superadmin | api_post_delete |
|  3 | Superadmin | api_post_edit   |
|  4 | Admin      | api_post_create |
|  5 | Admin      | api_post_edit   |
|  6 | Basic      | api_post_create |
+----+------------+-----------------+
6 rows in set (0.00 sec)

mysql> select * from easy_acl_role;
+----+------------+
| id | name       |
+----+------------+
|  1 | Superadmin |
|  2 | Admin      |
|  3 | Basic      |
+----+------------+
3 rows in set (0.00 sec)

mysql> select * from easy_acl_route;
+----+-----------------+---------+-----------------+
| id | name            | methods | path            |
+----+-----------------+---------+-----------------+
|  1 | api_post_create | POST    | /api/posts      |
|  2 | api_post_delete | DELETE  | /api/posts/{id} |
|  3 | api_post_edit   | PUT     | /api/posts/{id} |
+----+-----------------+---------+-----------------+
3 rows in set (0.00 sec)

如你所见,三个EasyAcl表被填充了在config/packages/programarivm_easy_acl.yaml中包含的数据,但是定义您的用户的身份取决于你。

如何将Superadmin身份设置为alice的示例

use Programarivm\EasyAclBundle\Entity\Identity;

...

$user = self::$em->getRepository('App:User')->findOneBy(['username' => 'alice');
$role = self::$em->getRepository('EasyAclBundle:Role')->findOneBy(['name' => 'Superadmin']);

$this->em->persist(
    (new Identity())
        ->setUser($user)
        ->setRole($role)
);

...

$this->em->flush();
mysql> select * from easy_acl_identity;
+----+---------+---------+
| id | role_id | user_id |
+----+---------+---------+
|  1 |       1 |       1 |
+----+---------+---------+
1 row in set (0.00 sec)

最后,权限存储库可以帮助你确定特定角色是否可以访问给定的资源

$isAllowed = $this->em
                ->getRepository('EasyAclBundle:Permission')
                ->isAllowed('Superadmin', 'api_post_show');

更具体地说,下面的示例展示了如何在event subscriber中使用权限存储库来授权JWT令牌。

// src/EventSubscriber/TokenSubscriber.php

namespace App\EventSubscriber;

use App\Controller\AccessTokenController;
use Doctrine\ORM\EntityManagerInterface;
use Firebase\JWT\JWT;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\KernelEvents;

class TokenSubscriber implements EventSubscriberInterface
{
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function onKernelController(ControllerEvent $event)
    {
        $controller = $event->getController();

        // when a controller class defines multiple action methods, the controller
        // is returned as [$controllerInstance, 'methodName']
        if (is_array($controller)) {
            $controller = $controller[0];
        }

        if ($controller instanceof AccessTokenController) {
            $jwt = substr($event->getRequest()->headers->get('Authorization'), 7);

            try {
                $decoded = JWT::decode($jwt, getenv('JWT_SECRET'), ['HS256']);
            } catch (\Exception $e) {
                throw new AccessDeniedHttpException('Whoops! Access denied.');
            }

            $user = $this->em->getRepository('App:User')
                        ->findOneBy(['id' => $decoded->sub]);

            $identity = $this->em->getRepository('EasyAclBundle:Identity')
                            ->findBy(['user' => $user]);

            $rolename = $identity[0]->getRole()->getName();
            $routename = $event->getRequest()->get('_route');

            $isAllowed = $this->em->getRepository('EasyAclBundle:Permission')
                            ->isAllowed($rolename, $routename);

            if (!$isAllowed) {
                throw new AccessDeniedHttpException('Whoops! Access denied.');
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::CONTROLLER => 'onKernelController',
        ];
    }
}

EasyAcl使用方法

该包为您提供了Programarivm\EasyAclBundle\EasyAcl,您可以使用它以友好、面向对象的方式访问YAML配置文件中的包信息。

示例

// src/DataFixtures/EasyAcl/RoleFixtures.php

namespace App\DataFixtures\EasyAcl;

use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Programarivm\EasyAclBundle\EasyAcl;
use Programarivm\EasyAclBundle\Entity\Role;

class RoleFixtures extends Fixture implements FixtureGroupInterface
{
    private $easyAcl;

    public function __construct(EasyAcl $easyAcl)
    {
        $this->easyAcl = $easyAcl;
    }

    public function load(ObjectManager $manager)
    {
        foreach ($this->easyAcl->getPermission() as $key => $permission) {
            $role = (new Role())->setName($permission['role']);
            $manager->persist($role);
            $this->addReference("role-$key", $role);
        }

        $manager->flush();
    }

    public static function getGroups(): array
    {
        return [
            'easy-acl',
        ];
    }
}

示例

// src/DataFixtures/EasyAcl/IdentityFixtures.php

namespace App\DataFixtures\EasyAcl;

use App\DataFixtures\UserFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Programarivm\EasyAclBundle\EasyAcl;
use Programarivm\EasyAclBundle\Entity\Identity;

class IdentityFixtures extends Fixture implements FixtureGroupInterface, DependentFixtureInterface
{
    private $easyAcl;

    public function __construct(EasyAcl $easyAcl)
    {
        $this->easyAcl = $easyAcl;
    }

    public function load(ObjectManager $manager)
    {
        for ($i = 0; $i < UserFixtures::N; $i++) {
            $index = rand(0, count($this->easyAcl->getPermission())-1);
            $user = $this->getReference("user-$i");
            $role = $this->getReference("role-$index");
            $manager->persist(
                (new Identity())
                    ->setUser($user)
                    ->setRole($role)
            );
        }

        $manager->flush();
    }

    public static function getGroups(): array
    {
        return [
            'easy-acl',
        ];
    }

    public function getDependencies(): array
    {
        return [
            RoleFixtures::class,
            UserFixtures::class,
        ];
    }
}

贡献

你能帮助使这个Symfony包变得更好吗?

谢谢。