DirectoryTree / Authorization

Easy, native Laravel user authorization.
MIT License
162 stars 7 forks source link

Authorization Cache #10

Closed mkinyua53 closed 4 months ago

mkinyua53 commented 4 months ago

How do you properly set Cache to prevent permissions from being loaded on each request?

I have this currently in AuthServiceProvider

        Authorization::cacheKey('my-permissions');
        Authorization::cacheExpiresIn(now()->addWeek());

But looking at both Telescope and Pulse, the cache key is never retrieved, and, I can see multiple requests for permissions in Telescope.

Dumping the cache returns null.

dd(Authorization::cacheExpiresIn(), Authorization::cacheKey(), \Cache::get(Authorization::cacheKey()));

image

stevebauman commented 4 months ago

Hi @mkinyua53,

Caching should be automatically enabled via Authorization::$cachesPermissions:

https://github.com/DirectoryTree/Authorization/blob/d42c519ef2016d998198c4d34c63d5ea5d6237ea/src/Authorization.php#L30-L35

https://github.com/DirectoryTree/Authorization/blob/d42c519ef2016d998198c4d34c63d5ea5d6237ea/src/PermissionRegistrar.php#L60-L64

Authorization will use your default cache driver. What do you have it set to in your .env (CACHE_DRIVER=)?

mkinyua53 commented 4 months ago

file on my local machine, and redis on production servers.

As you can see below, my-permissions which is the key I have set using the cacheKey method is never hit even once. This is from Pulse

direc

stevebauman commented 4 months ago

@mkinyua53 Where in the service provider are you calling Authorization::cacheKey('my-permissions')?

Try setting it in the register method of the AuthServiceProvider, as the package service provider will boot first, registering permissions and calling upon the cache before your AuthServiceProvider is hit. Let me know the result!

class AuthServiceProvider extends ServiceProvider
{
    // ...

    public function register(): void
    {
        parent::register();

        Authorization::cacheKey('...');
    }
mkinyua53 commented 4 months ago

I was calling it in the boot() method. I have changed to your suggestion in the register() method and still the cache is not being hit.

stevebauman commented 4 months ago

Ok thanks for trying that.

Have you ran the required migrations yet? I just tested this locally and it works as expected

Also, have you disabled registering the permissions in the gate via Authorization::disableGateRegistration()?

mkinyua53 commented 4 months ago

This is my 'complete' AuthServiceProvider


<?php

namespace App\Providers;

use Opcodes\LogViewer\LogFile;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use DirectoryTree\Authorization\Authorization;
use App\Models\User;
use App\Models\Role;
use App\Models\Permission;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        Authorization::useUserModel(User::class);
        Authorization::useRoleModel(Role::class);
        Authorization::usePermissionModel(Permission::class);

       /*
       ...
      */
    }

    public function register()
    {
        parent::register();

        Authorization::cacheKey('my-permissions');
        Authorization::cacheExpiresIn(now()->addWeek());
    }
}
stevebauman commented 4 months ago

Thanks @mkinyua53 -- but have you ran migrations yet using php artisan migrate so the authorization tables have been created?

mkinyua53 commented 4 months ago

Yes. This is a project I started in 2018 while it was still larapacks....

stevebauman commented 4 months ago

Strange... If you don't override the cache key, is anything returned when you call cache(Authorization::cacheKey())? Or just null?

mkinyua53 commented 4 months ago

Calling cache(Authorization::cacheKey()) returns a collection of permissions as expected. But every time you run hasPermission($permission), it runs a database query, completely ignoring the cache.

I have submitted a pull request that fixes that, by looking for the $permission in the collection from cache, and using Cache::remember().