Skip to content

Authorization

The Module Manager provides a comprehensive authorization system that automatically integrates with Laravel policies and Filament resources.

Policy Loading

Module Manager loads all the policies in App\Policies\ModuleName\ModelNamePolicy. For example, if you have a Post model in the Blog module, the policy would be located at App\Policies\Blog\PostPolicy.

This approach allows you to define policies at the application level, giving you full control over module authorization.

Policy Generation

To streamline creating policies for your modules, Module Manager includes a command that generates policy files for your models:

bash
php artisan mm:generate-policies

# Or for a specific module
php artisan mm:generate-policies --module=Blog

See the Generate Policies documentation for more details.

Authorization Helpers

Basic Authorization

The Module Manager provides a helper function to check if a user has access to perform actions on models:

php
use ModuleManager\ModuleManager\Enums\AuthorizeAction;

// Check permission using enum
$canCreate = authorizeAction(AuthorizeAction::CREATE, Post::class);

// Check permission on a model instance
$canUpdate = authorizeAction(AuthorizeAction::UPDATE, $post);

// You can also use string values, but enum is preferred for type safety
$canView = authorizeAction('view', $post);

The authorizeAction() helper checks if the user has permission to perform the specified action on the model. It returns true or false.

If the policy is not defined, the default behavior returns true (but you can configure this in the Module Manager config).

Policy Checker Facade

For more complex authorization scenarios, Module Manager provides a PolicyChecker facade that offers a fluent interface:

php
use ModuleManager\ModuleManager\Enums\AuthorizeAction;
use ModuleManager\ModuleManager\Facades\PolicyChecker;

// Basic check with enum
$canAccess = PolicyChecker::from(AuthorizeAction::VIEW, $post)->validate();

// Multiple checks - ALL must pass (logical AND)
$canManage = PolicyChecker::from(AuthorizeAction::CREATE, Post::class)
    ->and(AuthorizeAction::UPDATE, $post)
    ->validate();

// Multiple checks - ANY should pass (logical OR)
$hasAccess = PolicyChecker::from(AuthorizeAction::VIEW, $post)
    ->or(AuthorizeAction::UPDATE, $post)
    ->anyOf()
    ->validate();

Blade Directive

In Blade templates, you can use the @authorizeAction directive:

php
@authorizeAction(AuthorizeAction::CREATE, \Modules\Blog\Models\Post::class)
    <button>Create Post</button>
@endauthorizeAction

ConfigurableResource Integration

The ConfigurableResource class automatically integrates with the authorization system. When a resource extends this class, all standard Filament authorization methods (canViewAny, canCreate, etc.) are automatically handled through the corresponding policy methods:

php
// In your resource class
use ModuleManager\ModuleManager\Filament\Panels\ConfigurableResource;

class PostResource extends ConfigurableResource
{
    protected static string $model = Post::class;

    // No need to manually override canViewAny(), canCreate(), etc.
    // They are automatically handled by the Module Manager!
}

Creating Policies

Here's an example of a policy that would work with Module Manager:

php
<?php

namespace App\Policies\Blog;

use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Builder;
use Modules\Blog\Models\Post;

class PostPolicy
{
    use HandlesAuthorization;

    public function viewAny(User $user): bool
    {
        return true; // Everyone can view posts
    }

    public function view(User $user, Post $post): bool
    {
        return $post->user_id === $user->id || $user->hasRole('admin');
    }

    public function viewRow(User $user, Builder $query): Builder
    {
        // Special method that allows row-level filtering
        // in resource table listings
        return $query->where(function (Builder $query) use ($user) {
            $query->where('user_id', $user->id)
                ->orWhere('is_public', true);
        });
    }

    public function create(User $user): bool
    {
        return true; // Anyone can create posts
    }

    public function update(User $user, Post $post): bool
    {
        return $post->user_id === $user->id;
    }

    public function delete(User $user, Post $post): bool
    {
        return $post->user_id === $user->id || $user->hasRole('admin');
    }

    // Additional policy methods...
    public function restore(User $user, Post $post): bool
    {
        return $user->hasRole('admin');
    }

    public function forceDelete(User $user, Post $post): bool
    {
        return $user->hasRole('admin');
    }
}

Multi-Tenancy Considerations

When using multi-tenancy, policies should also check tenant access when appropriate:

php
public function view(User $user, Post $post): bool
{
    // First, check tenant access if multi-tenancy is enabled
    if (isMultiTenant() && tenant()->getKey() !== $post->getTenantId()) {
        return false;
    }

    // Then check normal permissions
    return $post->user_id === $user->id || $user->hasRole('admin');
}

Disabling Authorization

You can globally disable permission checking by setting the check_permissions key to false in the Module Manager configuration:

php
// config/module-manager.php
return [
    'check_permissions' => false,
    // ...
];

Additional Methods

The authorization system in Module Manager includes comprehensive support for all policy methods defined in the AuthorizeAction enum:

  • viewAny (AuthorizeAction::VIEW_ANY) - Can the user view any records?
  • view (AuthorizeAction::VIEW) - Can the user view a specific record?
  • create (AuthorizeAction::CREATE) - Can the user create new records?
  • update (AuthorizeAction::UPDATE) - Can the user update a specific record?
  • delete (AuthorizeAction::DELETE) - Can the user delete a specific record?
  • deleteAny (AuthorizeAction::DELETE_ANY) - Can the user delete any records?
  • restore (AuthorizeAction::RESTORE) - Can the user restore a specific soft-deleted record?
  • forceDelete (AuthorizeAction::FORCE_DELETE) - Can the user permanently delete a specific record?
  • updateAny (AuthorizeAction::UPDATE_ANY) - Can the user update any records?
  • reorder (AuthorizeAction::REORDER) - Can the user reorder records?
  • viewRow - Filter which specific rows a user can view