Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

janosk's avatar
Level 23

Dinamically generate Gates for permission control

Hi everyone!

I know there are several very well written role/permission package for lavarel, but I decided to go with a custom one from scratch because I need only basic rules. Since 90% of the time I only need two cases, one in which I grant complete access to a resource, and another where the user can only access/modify his/her own resource (own profile, post, comment, etc) I found a rather simple approach.

I just can't get rid of the idea, that it is too simple to be true :) So a would appretiate if any of you could take a moment, and point out if it is a bad practice for some reason. The approach is working perfectly fine by the way, so i have no issues at all.

Basicly I have a permissions table with an action_name column for the gate name and a few (right now) irrelevant column like title or description. And of course I have a pivot table to pair the users and the permissions in a many to many relationship.

Then I simply loop through the permissions in the AuthServiceProvider and generate a gate for every record, where I check if there is a match in the pivot table and if the user is the "owner" of the optional model I can provide. Since these are (seems to be) valid and working Gates, i can use them in middlewares, controllers, blade directives, etc. Which I like very much. But is it ok to generate them like this?

Thanks in advance for the feedback!

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot(Gate $gate)
    {
        $this->registerPolicies();

        /**
         * Override any policy/authorization
         */
        $gate->before(function ($user) {
            if ($user->isAdmin()) return true;
        });

        /**
         * Generate gates for every permission
         */
        $permissions = Permission::all();

        foreach ($permissions as $permission) {
            IlluminateGate::define($permission->action_name, function ($user, $model = NULL) use ($permission) {
                $hasPermission = $user->permissions()->where('permission_id', $permission->id)->exists();

                if (! empty($model)) {
                    $modelUserID = $model instanceof \App\User ? $model->id : $model->user_id;

                    return ($hasPermission && $user->id === $modelUserID);
                }
                
                return $hasPermission;
            });
        }
    }
0 likes
2 replies
bobbybouwmann's avatar
Level 88

The internals of Laravel is doing the exact same thing for policies and using the Gate facade as well. This is perfectly fine ;)

You can do one more improvement and that is adding caching for the permission queries. If you get a lot of permissions the pages might load a bit slower ;)

1 like
janosk's avatar
Level 23

Thank you! That is one more thing i didn't know, but that is why i am here :D

Caching is definitely on my list. Now that i know, this is not a wrong way to do permissions, will continue on that. Thanks for the tip!

Please or to participate in this conversation.