dmytrof/access-permissions-bundle

Symfony AccessPermissionsBundle

安装次数: 6,399

依赖项: 0

建议者: 0

安全: 0

星级: 1

关注者: 1

分支: 0

公开问题: 0

类型:symfony-bundle

1.2.1 2021-06-18 11:47 UTC

This package is auto-updated.

Last update: 2024-09-18 18:43:51 UTC


README

此包可以帮助您为您的Symfony 4/5应用程序创建访问权限

安装

步骤1:安装包

$ composer require dmytrof/access-permissions-bundle 

步骤2:启用包

<?php
    // config/bundles.php
    
    return [
        // ...
        Dmytrof\AccessPermissionsBundle\DmytrofAccessPermissionsBundle::class => ['all' => true],
    ];

用法

阅读symfony/security的官方文档,并将安全组件安装到您的项目中。

1. 为Article实体创建投票者

    // src/Security/ArticleVoter.php
    
    use App\Model\{Article, Author};
    use Dmytrof\AccessPermissionsBundle\Security\{AbstractVoter, CRUDVoterInterface, Traits\CRUDVoterTrait};
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    
    class ArticleVoter extends AbstractVoter implements CRUDVoterInterface
    {
        use CRUDVoterTrait;
    
        // Put needed resources to subject (Article, Category etc.)
        protected const SUBJECT = [
            Article::class,
        ];
    
        public const PREFIX = 'app.article.';
    
        public const VIEW   = self::PREFIX.'view';
        public const CREATE = self::PREFIX.'create';
        public const EDIT   = self::PREFIX.'edit';
        public const DELETE = self::PREFIX.'delete';
    
        public const ATTRIBUTES = [
            self::VIEW,
            self::CREATE,
            self::EDIT,
            self::DELETE,
        ];
    }

2. 将AdminInterface添加到您的User模型中

    // src/Entity/User.php

    use Symfony\Component\Security\Core\User\UserInterface;
    use Dmytrof\AccessPermissionsBundle\Security\AdminInterface;
    
    class User implements UserInterface, AdminInterface
    {
        //.....
        
        /**
         * Returns admin access atributes
         */
        public function getAdminAccessAttributes(): array
        {
            // Return saved attributes from DB
            return [
                ArticleVoter::getViewAttribute(),
                ArticleVoter::getCreateAttribute(),
                ArticleVoter::getEditAttribute(),
            ];
        }
        
        /**
         * Returns roles
         */
        public function getRoles(): array
        {
            $roles = $this->roles;
            // guarantee every user at least has ROLE_USER
            $roles[] = 'ROLE_USER';
            if ($this->isAdmin()) {
                $roles[] = 'ROLE_ADMIN';
            }
        
            return array_unique($roles);
        }
        //....
    }

3. 在控制器中添加访问检查

    //src/Controller/ArticleController.php
    
    /**
     * @Route("/api/articles")
     */
    class ArticleController extends AbstractController
    {
        /**
         * @Route("/", methods={"GET"})
         */
        public function getAll(Request $request)
        {
            $this->denyAccessUnlessGranted(ArticleVoter::getViewAttribute());
    
            // Fetch article from DB and return response
        }
    }

此时,AccessDecisionManager "询问" ArticleVoter是否可以RoleAdmin来查看

    // Dmytrof\AccessPermissionsBundle\Security\AbstractVoter.php;
    
    /**
     * Checks if admin has access to attribute
     */
    protected function canRoleAdmin(string $attribute, TokenInterface $token, $subject = null): bool
    {
        $admin = $token->getUser();
        if (!$admin instanceof AdminInterface) {
            return true;
        }
        return in_array($attribute, $admin->getAdminAccessAttributes());
    }

您可以为在security.yaml中定义的任何角色或添加到RolesContainer中的角色编写"can-method"。

    security:
        role_hierarchy:
            ROLE_AUTHOR
            ROLE_ADMIN: ROLE_USER
            ROLE_SUPER_ADMIN: ROLE_ADMIN 

重要提示

    /** @var \Dmytrof\AccessPermissionsBundle\Service\RolesContainer $rolesContainer */
    $rolesContainer->addRole('ROLE_ANY');

投票者首先尝试调用canRoleAuthorEdit(其中RoleAuthor - 分类的角色ROLE_AUTHOR,Edit - ArticleVoter::EDIT的简写属性)

    // src/Security/ArticleVoter.php
    
    /**
     * Checks if ROLE_AUTHOR can EDIT the article
     */
    protected function canRoleAuthorEdit(TokenInterface $token, $subject = null): bool
    {
        return $subject instanceof Article  // Subject is Article
            && $token->getUser() instanceof Author  // Authinticated user is Author
            && $subject->getAuthor() === $token->getUser(); // Authenticated Author is author of the Article
    }
    
    /**
     * Checks if ROLE_AUTHOR can VIEW, CREATE, DELETE the article
     */
    protected function canRoleAuthor(string $attribute, TokenInterface $token, $subject = null): bool
    {
        switch($attribute) {
            case static::VIEW:
            case static::CREATE:
                return true;
            default:
                return false;
        }
    }

记住

  1. 投票者尝试调用canRoleAuthorEdit
  2. 如果方法不存在,将调用canRoleAuthor
  3. 如果方法不存在,将调用can

4. 添加属性标签和描述

在翻译文件夹中创建access_attributes.en.yaml

    // translations/access_attributes.en.yaml
    
    app:
        label: My application
        attributes:
            create:
                label: Create
            view:
                label: View
            edit:
                label: Edit
            delete:
                label: Delete
        subjects:
            article:
                label: Articles
                attributes:
                    view:
                        label: View articles
                        description: Access to view article(s)
                    create:
                        label: Create new articles
                    # edit - default label app.attributes.edit.label will be used
                    # delete - default label app.attributes.delete.label will be used
            author:
                label: Authors
                # attributes - default app.attributes will be used

5. 管理用户属性

使用表单类型AccessAttributesChoiceTypeAccessAttributesCollectionType在您的用户表单类型中管理用户的访问属性。

要在您的API中获取所有访问属性及其描述,请向UserController添加操作。

    // src/Controller/UserController.php
    
    public function getAccessAttributes(VotersContainer $votersContainer)
    {
        return [
            'attributes' => $votersContainer->getAttributeDescriptionsCollection()->sort()->getAsArray()
        ];
    }