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

mdev11's avatar

Dynamic authorization for different models

I have a table for permissions:

id | permission 
1  | view-post
2  | edit-post

A table for roles:

id | role
1  | moderator
2  | editor

Many-to-many relationship role_permission:

id | role_id | permission_id
1  |    1    |       1

I use policies:

class PostPolicy
{
    public function before(User $user){
    	if($user->role_id == 1){
        	return true;
        }
	}

    public function viewPost(User $user)
	{
       return $user->hasPermission('view-post');
    }
}

User model:

public function hasPermission($permission){
    return $this->join('role_permissions AS rp', 'rp.role_id', 'users.role_id')
			->join('permissions AS p', 'p.id', 'rp.permission_id')
			->where('permission', $permission)
			->exists();
}

I need to check if the user is authorized to view a post for example with a redirect, not an exception.

Is there a way to make it dynamically as some packages like Spatie, Laratrust do?

0 likes
7 replies
rodrigo.pedra's avatar

You could:

  • Extend the Illuminate\Auth\Middleware\Authorize middleware
  • Override its handle method and write your custom redirect logic
  • Modify your app's App\Http\Kernel $routeMiddleware property, so the 'can' middleware points to your extended one.

or:

  • Register an exception handling in your app's App\Exceptions\Handler@register class method
  • Add a renderable to handle the Illuminate\Auth\Access\AuthorizationException
  • Return a redirect response from this exception handler

More info on this second approach at the docs: https://laravel.com/docs/9.x/errors#rendering-exceptions

mdev11's avatar

@rodrigo.pedra

Thanks. That's really useful and new to me. But I mean the authorization itself in the first place. Should I use gates, in this case, to be dynamic?

rodrigo.pedra's avatar

@mdev11

Well, I suggested you to handle Illuminate\Auth\Access\AuthorizationException, which is the exception thrown when there is an authorization failure, or to extend the Illuminate\Auth\Middleware\Authorize middleware, which is responsible for handling the authorization for routes.

Those should allow you to handle your authorization workflow dynamic enough.

Mind, those have their authentication counter-parts, which were not suggested in any means.

If you want to use Gates you can try using the Gate before and after filters, or adding a local before or after methods to a Policy.

Docs on Gate global filters:

Docs on Policy filters:

mdev11's avatar

@rodrigo.pedra

I see. But for the exception and middleware part, I think it can't be used within a view, Right?

I need to be able to check in view blade files for authorization too.

rodrigo.pedra's avatar

@mdev11

I need to check if the user is authorized to view a post for example with a redirect, not an exception.

From your description, I thought you wanted to handle exceptions and decide on redirects, for example.

You can use blade directives such as @if, or you can create your own blade directive:

inside a service provider do:

use Illuminate\Support\Facades\Blade;
 
public function boot()
{
    Blade::if('hasPermission', function ($permission) {
        return auth()->user()->hasPermission($permission);
    });
}

And then in any view you can:

@hasPermission('view-post')
    ...
@endhasPermission

More info at the docs:

https://laravel.com/docs/9.x/blade#custom-if-statements

One question:

What is holding you to use a third-part package? They will cover many other cases and be more efficient.

For example, your permission check method makes a database call on every check. If your view has dozens of checks, such when iterating a collection in a view, it will make dozens of database calls.

This is the kind of thing that has already been solved by those packages.

mdev11's avatar

@rodrigo.pedra

I'm not using a package because it's not only roles. There are branches, Each branch has specific features and roles related to these features.

Some of these packages have something called teams. But not sure if that's the case here.

As there will be a super admin with all features and roles from the main branch and admins for each branch.

Please or to participate in this conversation.