spatie/laravel-permission

Checking permissions directly on routes does not work

Ferks-FK opened this issue · 12 comments

Describe the bug
Apparently the thing about checking a permission directly on a route group using the can provided by Illuminate\Auth\Middleware\Authorize::class is not working correctly.

Error: Attempt to read property "guard_name" on string {"userId":1,"exception":"[object] (ErrorException(code: 0): Attempt to read property \"guard_name\" on string at /var/www/teste/teste/vendor/spatie/laravel-permission/src/Traits/HasPermissions.php:221)

Versions
You can use composer show to get the version numbers of:

  • spatie/laravel-permission: 5.10.2
  • laravel/framework: v9.52.9

PHP version: 8.2

Database version: 10.11.4-MariaDB-1:10.11.4+maria~ubu2204 - mariadb.org

To Reproduce
Steps to reproduce the behavior:

  • Do the default installation of the package.
  • Set permissions/roles etc.
  • Clear the cache.
  • Try checking for a permission directly on the routes.

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

Route::group(['middleware' => ['can:admin.admins.create'], 'prefix' => 'admin_settings'], function() {
        Route::get('/', [AdminController::class, 'index'])->name('settings.index');
        Route::get('/create', [AdminController::class, 'create'])->name('settings.create');
});

Example Application
Not has.

Expected behavior
I believe it should validate the permission, if not, give insufficient permission error.

Additional context
I tested with the can method of laravel, and also with the permission method provided by the package.
All return the same error.
Reference: https://spatie.be/docs/laravel-permission/v5/basic-usage/middleware

Taking a quick look at the package code, I did the following:
image

And I got the following:
image

I believe the part where it has $userPermission->guard_name will never work, because it is a string.

Environment (please complete the following information, because it helps us investigate better):

  • OS: [Ubuntu]
  • Version [22.04]
drbyte commented

Is this specific to the Wildcard Permissions feature?

Is this specific to the Wildcard Permissions feature?
Can you better formulate your question?

drbyte commented

You quoted line 221 of v5 of the HasPermissions trait, which is inside the hasWildcardPermission function.

Does this routes issue you're reporting only occur when you have the wildcard-permissions feature enabled? Are you actually using wildcards?

You quoted line 221 of v5 of the HasPermissions trait, which is inside the hasWildcardPermission function.

Does this routes issue you're reporting only occur when you have the wildcard-permissions feature enabled? Are you actually using wildcards?

I just did the test, setting enable_wildcard_permission to false (before it was at true), and now everything seems to work
But I would really like to use the wildcards.

/**
* Return all the permissions the model has, both directly and via roles.
*/
public function getAllPermissions(): Collection
{
/** @var Collection $permissions */
$permissions = $this->permissions;
if (method_exists($this, 'roles')) {
$permissions = $permissions->merge($this->getPermissionsViaRoles());
}
return $permissions->sort()->values();
}

getAllPermissions() returns a permissions collection, not a strings collection,
maybe this: v5/prerequisites#content-must-not-have-a-permission-or-permissions-property-nor-a-permissions-method

/**
* Return all the permissions the model has, both directly and via roles.
*/
public function getAllPermissions(): Collection
{
/** @var Collection $permissions */
$permissions = $this->permissions;
if (method_exists($this, 'roles')) {
$permissions = $permissions->merge($this->getPermissionsViaRoles());
}
return $permissions->sort()->values();
}

getAllPermissions() returns a permissions collection, not a strings collection,
maybe this: v5/prerequisites#content-must-not-have-a-permission-or-permissions-property-nor-a-permissions-method

No, I don't have anything in my user model with those attributes or methods.
edit: why get all permissions to do a loop to fetch only some permissions?
Wouldn't it be better to do a where?

drbyte commented

Given that the Wildcard Permissions feature was overhauled in the 6.0-dev version of this package (pending release soon), do you mind testing this against that version?

Given that the Wildcard Permissions feature was overhauled in the 6.0-dev version of this package (pending release soon), do you mind testing this against that version?

Before I opened this problem, I installed version 6.0-dev and had the exact same problem

drbyte commented

Agreed. An app that demonstrates the problem would be very helpful.

The test suite has middleware and route tests for Wildcard permissions such as you described, and those tests are passing. eg:

/** @test */
public function a_user_can_access_a_route_protected_by_permission_middleware_if_have_this_permission()
{
Auth::login($this->testUser);
Permission::create(['name' => 'articles']);
$this->testUser->givePermissionTo('articles');
$this->assertEquals(
200,
$this->runMiddleware($this->permissionMiddleware, 'articles.edit')
);
}

I will try to get a test app live.

Well, strangely enough everything seems to work now.
I've tested several times, including redoing the whole database, and it seems to be working fine with the wildcard.
Closing this.