Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Acl Bundle Laravel Package

symfony/acl-bundle

Symfony ACL Bundle enables resource-based authorization using Access Control Lists. Define and check permissions on domain objects/resources to manage fine-grained access rules. Includes documentation and a PHPUnit-based test suite for verification.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/acl-bundle
    

    Ensure Symfony\Bundle\SecurityBundle\SecurityBundle is enabled in config/bundles.php.

  2. Basic Configuration: Add ACL configuration to config/packages/security.yaml:

    security:
        acl:
            connection: default
            cache: app.cache.acl
            object_identity_class: App\Security\Acl\ObjectIdentity
    
  3. Define Custom ObjectIdentity: Create a class to map your domain objects (e.g., Post, User) to ACL entries:

    namespace App\Security\Acl;
    
    use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
    
    class ObjectIdentity extends ObjectIdentity {}
    
  4. First ACL Check: Secure a controller action:

    use Symfony\Component\Security\Acl\Permission\MaskBuilder;
    
    public function edit(Post $post)
    {
        $aclProvider = $this->get('security.acl.provider');
        $oid = ObjectIdentity::fromDomainObject($post);
        $mask = MaskBuilder::MASK_EDIT;
    
        if (!$aclProvider->isGranted($mask, $oid, $this->getUser())) {
            throw $this->createAccessDeniedException();
        }
        // Proceed with edit logic
    }
    
  5. Database Setup: Run migrations to create ACL tables (default schema provided by the bundle). Example using Doctrine Migrations:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

Where to Look First

  • Bundle Documentation: Symfony ACL Bundle Docs
  • Default Schema: vendor/symfony/security-acl/Resources/doc/schema.sql
  • MaskBuilder: Symfony\Component\Security\Acl\Permission\MaskBuilder for permission constants
  • ObjectIdentity: How to map your domain objects to ACL entries

Implementation Patterns

Core Workflows

1. Defining Resources and Permissions

  • Resources: Map domain objects (e.g., Post, Comment) to ACL entries via ObjectIdentity.
    // Example: Custom ObjectIdentity for a Post
    class PostObjectIdentity extends ObjectIdentity
    {
        public static function fromDomainObject(Post $post): self
        {
            return new self('post', $post->getId());
        }
    }
    
  • Permissions: Use MaskBuilder to define granular permissions:
    $mask = MaskBuilder::MASK_EDIT | MaskBuilder::MASK_DELETE;
    

2. Setting Up ACL Rules

  • Via Fixtures: Seed initial ACL rules in a service or command:
    use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
    use Symfony\Component\Security\Acl\Permission\MaskBuilder;
    
    public function loadAclRules(AclProvider $aclProvider, User $user)
    {
        $postOid = ObjectIdentity::fromDomainObject($post);
        $acl = $aclProvider->createAcl($postOid);
        $acl->insertObjectAce($postOid, MaskBuilder::MASK_EDIT, $user);
        $aclProvider->updateAcl($acl);
    }
    
  • Via Events: Use security.acl.post_load to dynamically adjust permissions:
    $eventDispatcher->addListener('security.acl.post_load', function (AclEvent $event) {
        if ($event->getObjectIdentity()->getType() === 'post') {
            $event->setAcl($this->customAclForPost($event->getObjectIdentity()));
        }
    });
    

3. Checking Permissions

  • In Controllers:
    public function update(Post $post)
    {
        $aclProvider = $this->get('security.acl.provider');
        $oid = ObjectIdentity::fromDomainObject($post);
        $mask = MaskBuilder::MASK_EDIT;
    
        if (!$aclProvider->isGranted($mask, $oid, $this->getUser())) {
            throw $this->createAccessDeniedException();
        }
        // Proceed
    }
    
  • In Twig Templates:
    {% if is_granted('ROLE_USER') and app.acl.isGranted('EDIT', post) %}
        <a href="{{ path('post_edit', {'id': post.id}) }}">Edit</a>
    {% endif %}
    
    (Note: Requires custom Twig extension for ACL checks.)

4. Integration with Voters

Combine ACL with Symfony’s voter system for hybrid checks:

use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class PostVoter extends Voter
{
    public function vote(AuthenticationToken $token, $object, array $attributes)
    {
        if (!$object instanceof Post) {
            return false;
        }
        if (in_array('EDIT', $attributes)) {
            $aclProvider = $this->aclProvider;
            $oid = ObjectIdentity::fromDomainObject($object);
            return $aclProvider->isGranted(MaskBuilder::MASK_EDIT, $oid, $token->getUser());
        }
        return false;
    }
}

Integration Tips

Doctrine ORM

  • Automate ObjectIdentity: Use Doctrine lifecycle events to auto-generate ObjectIdentity for entities:
    use Doctrine\ORM\Event\LifecycleEventArgs;
    
    class PostListener
    {
        public function postLoad(Post $post, LifecycleEventArgs $args)
        {
            $post->setObjectIdentity(ObjectIdentity::fromDomainObject($post));
        }
    }
    

Caching

  • Enable PsrAclCache for performance:
    # config/packages/security.yaml
    security:
        acl:
            cache: app.cache.acl
    
    Clear cache when ACL rules change:
    $this->get('security.acl.cache')->clear();
    

Multi-Tenancy

  • Scope ACL checks by tenant:
    $oid = new ObjectIdentity('post', $post->getId(), $tenantId);
    

Bulk Operations

  • Use AclProvider to batch-update ACLs:
    $aclProvider = $this->get('security.acl.provider');
    $batch = $aclProvider->findAclsByObjectIdentity(ObjectIdentity::fromDomainObject($post));
    foreach ($batch as $acl) {
        $acl->insertObjectAce($oid, $mask, $user);
        $aclProvider->updateAcl($acl);
    }
    

Gotchas and Tips

Pitfalls

1. ObjectIdentity Mismatches

  • Issue: ACL checks fail due to incorrect ObjectIdentity (e.g., wrong type or ID).
  • Fix: Ensure ObjectIdentity matches the resource exactly:
    // Wrong: Different type or ID
    $oid = new ObjectIdentity('post', 123); // But post ID is 456
    // Correct: Use fromDomainObject()
    $oid = ObjectIdentity::fromDomainObject($post);
    

2. Permission Mask Confusion

  • Issue: Using raw integers instead of MaskBuilder constants.
  • Fix: Always use MaskBuilder for clarity:
    // Bad: Magic numbers
    $mask = 4; // What does 4 mean?
    // Good:
    $mask = MaskBuilder::MASK_EDIT;
    

3. Database Locking

  • Issue: Concurrent ACL updates can cause deadlocks.
  • Fix: Use transactions or optimistic locking:
    $entityManager->beginTransaction();
    try {
        $aclProvider->updateAcl($acl);
        $entityManager->commit();
    } catch (\Exception $e) {
        $entityManager->rollback();
        throw $e;
    }
    

4. Caching Stale ACLs

  • Issue: Cached ACLs don’t reflect recent changes.
  • Fix: Clear cache after updates:
    $this->get('security.acl.cache')->clear();
    

5. Symfony Security Integration

  • Issue: ACLs conflict with Symfony’s access_control or voters.
  • Fix: Use ACLs for object-level permissions and voters for coarse-grained checks:
    # config/packages/security.yaml
    security:
        access_control:
            - { path: ^/admin, roles: ROLE_ADMIN } # Coarse-grained
        # ACLs handle fine-grained checks in code
    

Debugging Tips

1. Inspect ACLs

Use the security.acl.dump command to debug ACL entries:

php bin/console security:acl:dump

2. Log ACL Checks

Enable debug logging for ACL

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
yandex/translate-api
voku/simple_html_dom
league/flysystem-vfs
bkwld/upchuck
filament/spatie-laravel-tags-plugin
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php