Skip to content

[Question] How to Handle Dynamic Roles Correctly? #492

@MansourM

Description

@MansourM

Hello,
Thank you for your great work on this awesome library! 🙏

This is my first time using Spatie Permission and Filament Shield in a project, and I have some fundamental questions about the correct/best way to handle dynamic roles.


Example Scenario for Better Context:

  • We have a ticketing system, where each ticket has a customer and an assigned_admin.
  • There are 2 main types of users:
    • customer
    • admin
  • Basic roles include:
    • panel_user: All users have this role to access the panel.
    • super_admin
    • admin
    • customer
    • Other admin roles with varying levels of access or responsibilities.

What is the Problem?

We have the following default permissions for resources:

  • view
  • view_any
  • create
  • update
  • restore
  • restore_any
  • replicate
  • reorder
  • delete
  • delete_any
  • force_delete
  • force_delete_any

However, these permissions alone are insufficient for all scenarios.
For instance, view_any in Filament makes the ticket list page visible to the user, but this is not granular enough for my use case. I need a more specific version of view_any:

  • Super Admin sees all tickets.
  • Admin sees only tickets assigned to them.
  • Customer sees only tickets they own.

Why Not Use Role Names Directly?

Most resources online suggest adding extra role checks, like user->hasRole('admin'). However, this approach has critical drawbacks:

  1. Role Renaming: What if I change the admin role name?
  2. Role Flexibility: What if I need several types of admins with different permissions?

Thus, I believe role names should only be used for fundamental roles like super_admin and panel_user. Using them for dynamic checks defeats the purpose of permissions.


Possible Solutions and Challenges

  1. Add More Fine-Grained Permissions:
    I could define additional permissions, such as:

    • view_all
    • edit_all
    • view_assigned
    • edit_assigned
    • view_owned
    • edit_owned

    This would work but would require creating many additional permissions for each resource, making the system harder to manage.

  2. Use Policies with Complex Logic:
    Modify policies like this:

    public function viewAny(User $user): bool
    {
        return $user->can('view_any_ticket');
    }

However, this approach has limitations:

  • For my version of viewAny, I need access to ticket data (which is not available here) to determine ownership or assignment.

Impact on Filament Shield Functionality:

A significant concern is how these changes affect the Filament panel.
One of Filament Shield's great features is its automatic handling of interactions and resource availability based on default permissions. Customizing these aspects might break functionality or lead to unintended behavior.

Key Concerns:

  1. How can I handle dynamic role-based permissions without directly relying on role names?
  2. Is there a way to implement fine-grained control without overwhelming the system with too many permissions?
  3. How can I ensure my customizations align with Filament Shield's built-in features and don’t break its default behavior?

I’ve been researching this issue, but most answers are very surface-level and rely on using role names, which I’m trying to avoid. I’d be extremely grateful if you could shed some light on the best practices for handling these scenarios.

Thank you in advance! 🙏

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions