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

alchemy/acl-bundle

Symfony bundle providing a simple ACL API. Configure object types, alias your UserRepository, and add Redis cache for access tokens. Exposes endpoints to list, upsert, and delete ACEs by user/group, object type/id, with permission masks and wildcards.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle (via Composer):

    composer require alchemy/acl-bundle
    
  2. Configure ACL Objects (in config/packages/alchemy_acl.yaml):

    alchemy_acl:
        objects:
            publication: App\Models\Publication
            asset: App\Models\Asset
    
  3. Alias UserRepository (in config/services.yaml):

    services:
        Alchemy\AclBundle\Repository\UserRepositoryInterface: '@App\Repositories\UserRepository'
    
  4. Enable Redis Cache (optional, in config/cache.php):

    'pools' => [
        'accessToken.cache' => [
            'adapter' => 'redis',
            'provider' => 'redis://redis',
        ],
    ],
    
  5. First Use Case: Grant a user full access to a publication via API:

    curl -X PUT http://your-app/permissions/ace \
         -H "Content-Type: application/json" \
         -d '{
             "userType": "user",
             "userId": "user-123",
             "objectType": "publication",
             "objectId": "pub-42",
             "mask": 7
         }'
    

Implementation Patterns

Core Workflows

  1. Permission Assignment:

    • Use PUT /permissions/ace for dynamic ACLs (e.g., admin dashboards).
    • Example: Grant a group edit access to all assets:
      {
          "userType": "group",
          "userId": "editors-group",
          "objectType": "asset",
          "objectId": null,  // Applies to all assets
          "mask": 4  // Edit permission (binary 100)
      }
      
  2. Permission Querying:

    • Fetch all ACEs for a user on publications:
      curl http://your-app/permissions/aces?userType=user&userId=user-123&objectType=publication
      
    • Use in Laravel services to check permissions:
      public function checkAccess($userId, $objectType, $objectId, $requiredMask) {
          $response = Http::get("/permissions/aces", [
              'userType' => 'user',
              'userId' => $userId,
              'objectType' => $objectType,
              'objectId' => $objectId,
          ]);
          $aces = json_decode($response, true);
          foreach ($aces as $ace) {
              if ($ace['mask'] & $requiredMask) return true;
          }
          return false;
      }
      
  3. Metadata Integration (v1.1.0+):

    • Attach metadata to ACEs for audit/compliance:
      {
          "userType": "user",
          "userId": "admin-456",
          "objectType": "publication",
          "objectId": "pub-42",
          "mask": 7,
          "metadata": {
              "reason": "editorial_override",
              "expires_at": "2024-12-31"
          }
      }
      
    • Query ACEs with metadata filters (custom endpoint or client-side filtering).
  4. Group-Based Permissions:

    • Assign permissions to groups (e.g., "editors") and sync group memberships via Laravel events:
      // In UserRepository
      public function addToGroup($userId, $groupId) {
          // Sync group membership
          $this->emit('group.updated', [$groupId]);
      }
      

Integration Tips

  • Laravel Service Layer: Create a facade or service to abstract API calls:

    namespace App\Services;
    
    use Illuminate\Support\Facades\Http;
    
    class AclService {
        public function hasAccess($userId, $objectType, $objectId, $permission) {
            $response = Http::get("/permissions/aces", [
                'userType' => 'user',
                'userId' => $userId,
                'objectType' => $objectType,
                'objectId' => $objectId,
            ]);
            $aces = json_decode($response, true);
            return collect($aces)->contains(fn($ace) => ($ace['mask'] & $permission));
        }
    }
    
  • Policy Integration: Extend Laravel’s Policy class to use the ACL bundle:

    namespace App\Policies;
    
    use App\Services\AclService;
    
    class PublicationPolicy {
        protected $acl;
    
        public function __construct(AclService $acl) {
            $this->acl = $acl;
        }
    
        public function edit($user, Publication $publication) {
            return $this->acl->hasAccess(
                $user->id,
                'publication',
                $publication->id,
                4  // Edit mask
            );
        }
    }
    
  • Event-Driven Sync: Listen for group.updated events to refresh cached permissions:

    Event::listen('group.updated', function ($groupId) {
        // Clear Redis cache for group-based ACEs
        Cache::forget("acl:group:{$groupId}");
    });
    
  • Middleware for API Routes: Protect API endpoints with ACL checks:

    Route::middleware(['acl:publication.edit'])->group(function () {
        Route::put('/publications/{id}', [PublicationController::class, 'update']);
    });
    

    (Requires custom middleware using the AclService.)


Gotchas and Tips

Pitfalls

  1. Mask Confusion:

    • The mask is a bitwise integer (e.g., 7 = 111 in binary = read/write/execute).
    • Gotcha: mask: 7 grants all permissions, but mask: 4 (edit) + mask: 2 (read) ≠ mask: 6 (read + edit) due to bitwise OR logic.
    • Fix: Use constants in your code:
      class PermissionMask {
          public const READ = 1;
          public const WRITE = 2;
          public const EXECUTE = 4;
      }
      
  2. Null ObjectId:

    • objectId: null applies the ACE to all objects of the objectType.
    • Gotcha: Overly broad rules (e.g., objectId: null for publication) can cause performance issues when querying ACEs.
    • Fix: Prefer specific objectId values unless global rules are intentional.
  3. Redis Cache Quirks:

    • The accessToken.cache pool must be named exactly accessToken.cache for auto-wiring.
    • Gotcha: If Redis fails, the bundle may throw cryptic errors about missing cache adapters.
    • Fix: Verify Redis is running and the pool is configured:
      framework:
          cache:
              pools:
                  accessToken.cache:  # Must match this name
                      adapter: cache.adapter.redis
      
  4. UserRepository Aliasing:

    • The bundle requires a custom UserRepositoryInterface implementation.
    • Gotcha: Forgetting to alias the service causes ServiceNotFoundException.
    • Fix: Double-check config/services.yaml:
      services:
          Alchemy\AclBundle\Repository\UserRepositoryInterface: '@App\Repositories\UserRepository'
      
  5. Metadata Limitations:

    • Metadata is stored in the database (not cached) and may bloat ACE tables.
    • Gotcha: Heavy metadata usage can slow down /permissions/aces queries.
    • Fix: Limit metadata to critical fields (e.g., reason, expires_at) and avoid large payloads.
  6. Symfony 7 Dependency Conflicts:

    • The bundle uses Symfony 7 components, which may conflict with Laravel’s symfony/* packages.
    • Gotcha: Composer installs duplicate versions of symfony/options-resolver, causing runtime errors.
    • Fix: Use composer.json overrides:
      "extra": {
          "laravel": {
              "dont-discover": ["symfony/*"]
          }
      }
      

Debugging Tips

  1. Enable API Debugging:

    • Check raw API responses for errors:
      curl -v http://your-app/permissions/aces
      
    • Look for 400 Bad Request errors if required fields (e.g., mask) are missing.
  2. Log ACE Queries:

    • Add logging to the AclService to trace permission checks:
      public function hasAccess($userId, $objectType, $objectId, $permission) {
          Log::debug("Checking ACL for user {$userId}, object {$objectType}/{$objectId}, mask {$permission}");
          // ... existing logic
      }
      
  3. Inspect Database:

    • Verify ACEs are stored correctly in the database (likely a table named `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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
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
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime