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

eggplantSword's avatar

Help Authorization Policies

I'm trying to add Authorization Policies to my project but I'm unsure how to recreate this logic. I have multiple user types (roles) such as:

  • SuperAdmin
  • Admin
  • Director
  • Profesor
  • Student

The SuperAdmin can do everything and see everything, the Admin can do almost anything and see what they created and the Director is limited to what they can do and see.

The Profesor and Student can't do anything except answer surveys or forums.

Right now I'm going to use as an example a Survey Section. These can be created, updated, deleted and can be seen by the SuperAdmin and the Admin can create, see all, but can only update and delete the Sections they created. The Director can only see them but can't create, update or delete them.

I created the Policy and this is what I have right now

class SectionPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can create survey sections.
     *
     * @param  \App\Models\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        return $user->isSuperAdmin() || $user->isAdmin();
    }

    /**
     * Determine whether the user can update the survey section.
     *
     * @param  \App\Models\User  $user
     * @param  \App\SurveySection  $surveySection
     * @return mixed
     */
    public function update(User $user, SurveySection $surveySection)
    {
        //
    }

    /**
     * Determine whether the user can delete the survey section.
     *
     * @param  \App\Models\User  $user
     * @param  \App\SurveySection  $surveySection
     * @return mixed
     */
    public function delete(User $user, SurveySection $surveySection)
    {
        //
    }
}

In my User Model I have these methods, the user can have multiple types, for example a user can be a profesor and a teacher at the same time, or a director and a teacher at the same time. The getUserTypeHighest is useful because it returns the highest authority user type the user has, so a director and teacher user will return highest user type as Director which has the most privileges.

public function hasUserType($id = [])
    {
        if (!is_array($id)) {
            $id = [$id];
        }
        return $this->userType()
                ->whereIn('id', $id)
                ->count() > 0;
    }

    public function getUserTypeHighest()
    {
        $types = $this->userType;
        $t = [];
        foreach ($types as $type) {
            $t[] = $type->pivot->user_type_id;
        }

        return min($t);
    }

    public function getUserTypes()
    {
        $types = $this->userType;
        $t = [];
        foreach ($types as $type) {
            $t[] = $type->pivot->user_type_id;
        }

        return $t;
    }

    public function isSuperAdmin()
    {
        return $this->hasUserType(UserType::SUPER_ADMIN);
    }

    public function isAdmin()
    {
        return $this->hasUserType(UserType::ADMIN);
    }

    public function isDirector()
    {
        return $this->hasUserType(UserType::DIRECTOR);
    }

    public function isProfesor()
    {
        return $this->hasUserType(UserType::PROFESOR);
    }

    public function isStudent()
    {
        return $this->hasUserType(UserType::STUDENT);
    }

When trying to create a new Survey Section I get a 403 when logged in as a SuperAdmin

public function store(SaveSectionRequest $request)
    {
        $this->authorize('create');

        DB::beginTransaction();
        $section = new SurveySection();
        $section->title = $request->title;
        $section->description = $request->description;
        $section->user_id = $request->user()->id;
        $section->save();
        DB::commit();

        return back();
    }

How can I recreate this logic in my policy?

0 likes
7 replies
jlrdw's avatar

You are probably going to need authorization policies with query scopes to differentiate who can see what.

That is unless you have completely different methods and views for each role.

Also are you aware that in the from scratch series he has several free videos on authorization. He demos a lot of different techniques.

Also have a look at: https://github.com/spatie/laravel-permission

eggplantSword's avatar

@jlrdw I'm watched the first video on the Authorization section of the Laravel from Scratch, and this model is pretty simple so I'm trying to get it to work at least the create which is the simplest one, only a SuperAdmin or Admin can create. But it's returning a 403 error and I'm not sure why

jlrdw's avatar

Under https://laravel.com/docs/7.x/authorization#policy-filters

Make sure you have like example:

public function before($user, $ability)
{
    if ($user->isSuperAdmin()) {
        return true;
    }
}

Add the or for admin as needed.

What page throws the 403. Are you attempting login at the time and trying to redirect somewhere. Or are you logged in and a create method is throwing the 403?

eggplantSword's avatar

@jlrdw I'm logged in as a SuperAdmin and when I try to create a new Survey Section I get the 403 error. I changed the create to this

public function create(User $user)
{
    if ($user->isSuperAdmin() || $user->isAdmin()) {
        return true;
    }
}

EDIT

I'm trying to implement it how the final video does, using the user_roles and so far so good, but how can I do what he does when he uses @can on blade in vue.js? Right now since I'm using Inertia.js I can get the user role via the Shared Data that Inertia has but I'm assuming there is a better way to check.

Also in the routes he adds a middleware, I'm confused about that as well, I already have a middleware that separated the routes be user role, the routes for this model are already in there like this, (I have to fix the update route so ignore it)

Route::group(['middleware' => ['role: admin, super']], function () {
    Route::resource('sections', 'SectionController');
    Route::post('sections/update/{id}', 'SectionController@update');
    Route::post('sections/questions/{id}', 'SectionController@deleteQuestions');
}

Do I still need to add it to each route?

jlrdw's avatar

can, can be used in Blade but normally I do it in controller similar to:

public function update(Request $request, Post $post) {
    if ($post->author !== auth()->user()->id || auth()->user()->cannot('edit posts'))
        abort(404);// or redirect, or whatever action 
    }
    //rest of method if all okay
}

I just like catching stuff at the method level. And sorry I don't have any good examples of doing that in Blade, but double check the documentation for examples, I know there are some there.

Also make sure you all retrieving the true in your code above.

eggplantSword's avatar

@jlrdw doing it in the method is even better I think that would work great, I'm going to keep trying!

jlrdw's avatar

At each step do a dd or an echo or use use browser development tools check your request and response to make sure you are retrieving what's expected.

The network tab has really helped speed things up for me when troubleshooting problems.

Please or to participate in this conversation.