spatie / laravel-permission

Associate users with roles and permissions
https://spatie.be/docs/laravel-permission
MIT License
12.04k stars 1.76k forks source link

Incorrect result of $user->hasRole('admin'); within the laravel model #2161

Closed abd1407 closed 1 year ago

abd1407 commented 2 years ago

I have when using Role either in the blade or in the model code. I am using Role inside the model function to return records depending on user role. For a normal user, I will return only those records that were inserted by him, and for an admin, I am returning all records. However, when I use $user->hasRole('admin'); it returns true for all users, even if they do not have admin privileges. Any role name returns true when it is in the roles table. I printed the user id on the web page to ensure that the user did not have any database roles. When this issue happens, blade @hasRole('admin') returns true for the same not admin logged user.

spatie/laravel-permission package version is 5.5.4. PHP version:  7.3 Database version: 5.x

Steps to reproduce the behavior: Use @hasRole('admin') in any model inside the booted() function and it will return true even if the user didn't have this role.

Here is my example code and/or tests showing the problem in my app:

Example Application

protected static function booted()
    {
        if(!empty(Auth::user()))
        {
            parent::boot();
            $user = Auth::user();

            $user_info = User::where('id',$user->id)->with('driverInfo','clientInfo','launderInfo')->first();

            // echo $user_info->launderInfo;
            // die();

            if($user->hasRole('admin'))
            {
                return;
            }
            elseif($user->hasRole('launder') && !empty($user_info->launderInfo))
            {
                $launder_id = $user_info->launderInfo->id;
                static::addGlobalScope('launder_id', function (Builder $builder)  use ($launder_id)
                {
                    $builder->where('launder_id', '=', $launder_id);
                });
            }
            elseif($user->hasRole('user')  && !empty($user_info->clientInfo))
            {
                $client_id = $user_info->clientInfo->id;

                static::addGlobalScope('client_id', function (Builder $builder) use ($client_id)
                {
                    $builder->where('client_id', '=', $client_id);
                });
            }
            elseif($user->hasRole('driver') && !empty($user_info->driverInfo))
            {

                $driver_id = $user_info->driverInfo->id;
                static::addGlobalScope('driver_id', function (Builder $builder)  use ($driver_id)
                {
                    $builder->where('driver_id', '=', $driver_id);
                });
            }
            else
            {
                static::addGlobalScope('id', function (Builder $builder)
                {
                    $builder->where('id', '=', 0);
                });
            }

        }// end if user empty
        else
        {
            return true;
        }
    }

Expected behavior:

The role function should return true only when the current user is assigned to this role. and the blade @role is unaffected.

 Additional context By the way, am I using the best way to filter model results depending on user roles?

PaolaRuby commented 2 years ago

Really hard to read if you don't use markdown correctly ```php

Example:

if($user->hasRole('admin'))
{
    return;
}

Current version is 5.5.5, not 5.5.4, hasRole is tested, probably is a problem with your implementation

For the example application, you must follow the steps on documentation laravel-permission/example-application

erikn69 commented 2 years ago

I test boot, everything is working as expected

abd1407 commented 2 years ago

Thank you for replay me. version updated to 5.5.5 but problem still. I found problem happened when I use data from 2 models that have booted function that including call for $user->hasRole() function. problem happened only when i use $user->hasRole() in model, this function return true to any role name exist in database although the current user never assigned to this role and false when this role not exist.

erikn69 commented 2 years ago

I test boot, everything is working as expected

Impossible to replicate

For the example application, you must follow the steps on documentation laravel-permission/example-application

Make a demo app on a fresh laravel instalation

abd1407 commented 2 years ago

I figured out exactly why the problem occurred. Occurs when User Model is used together hasRole function inside another model and both are called at the same time.

Model1

            $user_info = User::where('id',$user->id)->with('driverInfo','clientInfo','launderInfo')->first();

            if($user->hasRole('admin'))
            {
                return;
            }

Model2

             $user_info = User::where('id',$user->id)->with('launderInfo')->first();

            if($user->hasRole('admin'))
            {
                return;
            }

I change Model1 to :

            $driverInfo = Driver::where('user_id',$user->id)->first();
            $clientInfo = Client::where('user_id',$user->id)->first();
            $launderInfo = Launder::where('user_id',$user->id)->first();

Now every thing working fine. But this issue must be resolved from library side.

Sebastianoskiojoj commented 1 year ago

Mam podczas korzystania z roli albo w ostrzu, albo w kodzie modelu. Używam roli wewnątrz funkcji modelu do zwracania rekordów w zależności od roli użytkownika. Dla zwykłego użytkownika zwrócę tylko te rekordy, które zostały przez niego wstawione, a dla administratora zwracam wszystkie rekordy. Jednak gdy używam $user->hasRole('admin'); zwraca true dla wszystkich użytkowników, nawet jeśli nie mają uprawnień administratora. Każda nazwa roli zwraca prawdę, gdy znajduje się w tabeli ról. Wydrukowałem identyfikator użytkownika na stronie internetowej, aby upewnić się, że użytkownik nie ma żadnych ról w bazie danych. W przypadku wystąpienia tego problemu blade @hasRole('admin') zwraca wartość true dla tego samego użytkownika, który nie jest zalogowany jako administrator.

Wersja pakietu spatie/laravel-permission to 5.5.4. Wersja PHP: 7.3 Wersja bazy danych: 5.x

Kroki do odtworzenia zachowania: Użyj @hasRole('admin') w dowolnym modelu wewnątrz funkcji booted(), a zwróci true, nawet jeśli użytkownik nie miał tej roli.

Oto mój przykładowy kod i/lub testy pokazujące problem w mojej aplikacji:

Przykładowa aplikacja

protected static function booted()
    {
        if(!empty(Auth::user()))
        {
            parent::boot();
            $user = Auth::user();

            $user_info = User::where('id',$user->id)->with('driverInfo','clientInfo','launderInfo')->first();

            // echo $user_info->launderInfo;
            // die();

            if($user->hasRole('admin'))
            {
                return;
            }
            elseif($user->hasRole('launder') && !empty($user_info->launderInfo))
            {
                $launder_id = $user_info->launderInfo->id;
                static::addGlobalScope('launder_id', function (Builder $builder)  use ($launder_id)
                {
                    $builder->where('launder_id', '=', $launder_id);
                });
            }
            elseif($user->hasRole('user')  && !empty($user_info->clientInfo))
            {
                $client_id = $user_info->clientInfo->id;

                static::addGlobalScope('client_id', function (Builder $builder) use ($client_id)
                {
                    $builder->where('client_id', '=', $client_id);
                });
            }
            elseif($user->hasRole('driver') && !empty($user_info->driverInfo))
            {

                $driver_id = $user_info->driverInfo->id;
                static::addGlobalScope('driver_id', function (Builder $builder)  use ($driver_id)
                {
                    $builder->where('driver_id', '=', $driver_id);
                });
            }
            else
            {
                static::addGlobalScope('id', function (Builder $builder)
                {
                    $builder->where('id', '=', 0);
                });
            }

        }// end if user empty
        else
        {
            return true;
        }
    }

Oczekiwane zachowanie :

Funkcja roli powinna zwracać wartość true tylko wtedy, gdy bieżący użytkownik jest przypisany do tej roli. i ostrze@ROLEnie ma to wpływu.

 Dodatkowy kontekst A propos, czy używam najlepszego sposobu filtrowania wyników modelu w zależności od ról użytkownika?

art/logomark.svg