Laravel authorize for users and roles

88 Views Asked by At

I am trying to authorize Users and Roles in such a way that each user cannot have access to another's id when it comes to Editing. For example, if I enter the editing page for My Termins(Meetings)(in this case) http://localhost:8000/admin/termins/2/edit do not be able to access any meeting ID of another user in which I did not create that termin. So, when I manually type http://localhost:8000/admin/termins/1/edit, I can't access it, showing a 403 error.

My current Controller:

 public function edit($id)
    {
        $termin = Termin::findOrFail($id);

        $this->authorize('edit', $termin);

Rest of code...

My policy:

<?php


// app/Policies/TerminPolicy.php

namespace App\Policies;

use App\User;
use App\Termin;
use Illuminate\Auth\Access\HandlesAuthorization;

class TerminPolicy
{
    use HandlesAuthorization;

    public function edit(User $user, Termin $termin)
{
    \Log::info("User ID: {$user->id}, Created By ID: {$termin->created_by_id}");

    return $user->id === $termin->created_by_id;
}

    public function view(User $user, Termin $termin)
    {
        return $user->id === $termin->created_by_id;
    }
}

AuthServiceProvider:

<?php

namespace App\Providers;

use App\Policies\TerminPolicy;
use App\Role;
use App\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Termin::class => TerminPolicy::class,
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();
        $user = \Auth::user();

        
        if (! app()->runningInConsole()) {
            $roles = Role::with('permission')->get();

            $permissionArray = [];
            
            foreach ($roles as $role) {
                foreach ($role->permission as $permission) {
                    $permissionArray[$permission->title][] = $role->id;
                }
            }

            foreach ($permissionArray as $title => $roles) {
                Gate::define($title, function (User $user) use ($roles) {
                    return count(array_intersect($user->role->pluck('id')->toArray(), $roles));
                });
            }

        }
    }
}

User Model:

public function role()
    {
        return $this->belongsToMany(Role::class, 'role_user');
    }

Rest of code...

With this code, I always get error 403 This action is unauthorized when entering the edit page from any user. But, as I said, each user have to edit and see only their own Termin.

Thank you.

2

There are 2 best solutions below

15
afcyy On BEST ANSWER

The easiest solution would be to create a relationship between users and termin and access termin via auth()->user(). That way if Termin doesn't belong to the user they won't be able to access it.

public function edit($id)
{
    $termin = auth()->user()->termins()->findOrFail($id);
    $this->authorize('edit', $termin);
    
    //..Rest of the code
}

You already have created_by_id which stores user id so you could just define relationship like this

public function termins()
{
    return $this->hasMany(Termin::class, 'created_by_id');
}

Since you already defined relationship between users and termins you can also replace your policy

class TerminPolicy
{
    use HandlesAuthorization;

    public function edit(User $user, Termin $termin)
    {
        return $user->termins->contains($termin);
    }

    public function view(User $user, Termin $termin)
    {
        return $user->termins->contains($termin);
    }
}
0
Andi Gashi On

I'm sorry, it was my mistake in that I didn't clarify the problem and the relationship between my tables well.

I solved the problem as follows:

 public function edit(User $user, Termin $termin)
{
    return $user->id === $termin->created_by_id || $user->team->id === $termin->call_center_id || $user->id === $termin->assigned_to_id;

}

public function view(User $user, Termin $termin)
{
    return $user->id === $termin->created_by_id || $user->team->id === $termin->call_center_id || $user->id === $termin->assigned_to_id;
}

Controller:

public function show($id)
{
   $termin = Termin::findOrFail($id);
    if (Auth::user()->role[0]->id != 1) {
       $this->authorize('view', $termin);
    }

return view('admin.termins.show', compact('termin'));
}

public function edit($id)
{ 

    $termin = Termin::findOrFail($id);
    if (Auth::user()->role[0]->id != 1) {
       $this->authorize('edit', $termin);
    }
rest of the code...

Thank you @afcy