symfony_如何通过Symfony轻松管理ACL

symfony

秘密的ACL并非易事。 由于选民似乎是Symfony推荐的ACL的替代方法,因此我最近决定编写自己的易于使用的Symfony 5捆绑包,以管理应用程序中的访问控制列表(ACL)。

programarivm / easy-acl-bundle最初被编写为用于单页应用程序(SPA)的JWT身份验证API中使用,但如果不需要安全组件,它也可以在多种不同情况下提供帮助-在大多数情况下,该组件以我的拙见,它将特别适合于多页应用程序(MPA)处理会话。

EasyAclBundle完全依靠Doctrine实体和存储库来完成其工作,这意味着权限仅存储在数据库中。 就您的应用程序架构而言,这是不可知的。

话虽如此,这就是在事件订户中借助所谓的简单ACL存储库轻松地对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' ,
        ];
    }
}

如果您是经验丰富的开发人员,那么大多数代码都是不言自明的。 基本上,如果传入的访问令牌已成功解码,这意味着给定的用户已通过身份验证,则代码将尝试确定他们是否具有访问当前路由的正确权限。

...

$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);

...

只需两个简单的ACL存储库( IdentityPermission )即可确定用户是否可以访问当前路由。

组态

现在让我们看一下魔术的工作原理。 简而言之,这就是定义应用程序的路由:

# 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

因此,如果您的数据库架构现在已更新:

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

四个空表将添加到您的数据库中:

  • easy_acl_identity
  • easy_acl_permission
  • easy_acl_role
  • easy_acl_route

这四个与以下实体并驾齐驱:

和存储库:

最后, easy-acl:setup控制台命令是填充easy ACL表。

php bin/console easy-acl:setup
This will reset the ACL. Are you sure tocontinue ? (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表中填充了数据,但是当然可以由您来动态定义用户的身份,如下面的数据示例所示。

// 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,
        ];
    }
}

有关更多详细信息,该文档将指导您完成如何安装和设置简易ACL捆绑包的过程。

这就是今天的帖子结束的方式。 有帮助吗? 但愿如此。 在下面的评论中告诉我们!

您也可能对。。。有兴趣...

翻译自: https://hackernoon.com/how-to-manage-acls-in-symfony-the-easy-peasy-way-jc1r3yy7

symfony

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值