Skip to content

Commit

Permalink
Merge pull request #2381 from erikn69/patch-17
Browse files Browse the repository at this point in the history
[v6] fix BadMethodCallException: undefined methods hasAnyRole, hasAnyPermissions
  • Loading branch information
drbyte authored Mar 30, 2023
2 parents d764505 + 9384223 commit eea8e15
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/Exceptions/UnauthorizedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Spatie\Permission\Exceptions;

use Illuminate\Contracts\Auth\Access\Authorizable;
use Symfony\Component\HttpKernel\Exception\HttpException;

class UnauthorizedException extends HttpException
Expand Down Expand Up @@ -52,6 +53,13 @@ public static function forRolesOrPermissions(array $rolesOrPermissions): self
return $exception;
}

public static function missingTraitHasRoles(Authorizable $user): self
{
$class = get_class($user);

return new static(403, "Authorizable class `{$class}` must use Spatie\Permission\Traits\HasRoles trait.", null, []);
}

public static function notLoggedIn(): self
{
return new static(403, 'User is not logged in.', null, []);
Expand Down
17 changes: 11 additions & 6 deletions src/Middlewares/PermissionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@
namespace Spatie\Permission\Middlewares;

use Closure;
use Illuminate\Support\Facades\Auth;
use Spatie\Permission\Exceptions\UnauthorizedException;

class PermissionMiddleware
{
public function handle($request, Closure $next, $permission, $guard = null)
{
$authGuard = app('auth')->guard($guard);
$authGuard = Auth::guard($guard);

if ($authGuard->guest()) {
throw UnauthorizedException::notLoggedIn();
}

$user = $authGuard->user();

if (! method_exists($user, 'hasAnyPermission')) {
throw UnauthorizedException::missingTraitHasRoles($user);
}

$permissions = is_array($permission)
? $permission
: explode('|', $permission);

foreach ($permissions as $permission) {
if ($authGuard->user()->can($permission)) {
return $next($request);
}
if (! $user->canAny($permissions)) {
throw UnauthorizedException::forPermissions($permissions);
}

throw UnauthorizedException::forPermissions($permissions);
return $next($request);
}
}
8 changes: 7 additions & 1 deletion src/Middlewares/RoleMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ public function handle($request, Closure $next, $role, $guard = null)
throw UnauthorizedException::notLoggedIn();
}

$user = $authGuard->user();

if (! method_exists($user, 'hasAnyRole')) {
throw UnauthorizedException::missingTraitHasRoles($user);
}

$roles = is_array($role)
? $role
: explode('|', $role);

if (! $authGuard->user()->hasAnyRole($roles)) {
if (! $user->hasAnyRole($roles) && ! $user->can('')) {
throw UnauthorizedException::forRoles($roles);
}

Expand Down
8 changes: 7 additions & 1 deletion src/Middlewares/RoleOrPermissionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ public function handle($request, Closure $next, $roleOrPermission, $guard = null
throw UnauthorizedException::notLoggedIn();
}

$user = $authGuard->user();

if (! method_exists($user, 'hasAnyRole') || ! method_exists($user, 'hasAnyPermission')) {
throw UnauthorizedException::missingTraitHasRoles($user);
}

$rolesOrPermissions = is_array($roleOrPermission)
? $roleOrPermission
: explode('|', $roleOrPermission);

if (! $authGuard->user()->hasAnyRole($rolesOrPermissions) && ! $authGuard->user()->hasAnyPermission($rolesOrPermissions)) {
if (! $user->canAny($rolesOrPermissions) && ! $user->hasAnyRole($rolesOrPermissions)) {
throw UnauthorizedException::forRolesOrPermissions($rolesOrPermissions);
}

Expand Down
30 changes: 30 additions & 0 deletions tests/PermissionMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Gate;
use InvalidArgumentException;
use Spatie\Permission\Contracts\Permission;
use Spatie\Permission\Exceptions\UnauthorizedException;
use Spatie\Permission\Middlewares\PermissionMiddleware;
use Spatie\Permission\Tests\TestModels\UserWithoutHasRoles;

class PermissionMiddlewareTest extends TestCase
{
Expand Down Expand Up @@ -69,6 +71,21 @@ public function a_user_cannot_access_a_route_protected_by_the_permission_middlew
);
}

/** @test */
public function a_super_admin_user_can_access_a_route_protected_by_permission_middleware()
{
Auth::login($this->testUser);

Gate::before(function ($user, $ability) {
return $user->getKey() === $this->testUser->getKey() ? true : null;
});

$this->assertEquals(
200,
$this->runMiddleware($this->permissionMiddleware, 'edit-articles')
);
}

/** @test */
public function a_user_can_access_a_route_protected_by_permission_middleware_if_have_this_permission()
{
Expand Down Expand Up @@ -100,6 +117,19 @@ public function a_user_can_access_a_route_protected_by_this_permission_middlewar
);
}

/** @test */
public function a_user_cannot_access_a_route_protected_by_the_permission_middleware_if_have_not_has_roles_trait()
{
$userWithoutHasRoles = UserWithoutHasRoles::create(['email' => 'test_not_has_roles@user.com']);

Auth::login($userWithoutHasRoles);

$this->assertEquals(
403,
$this->runMiddleware($this->permissionMiddleware, 'edit-news')
);
}

/** @test */
public function a_user_cannot_access_a_route_protected_by_the_permission_middleware_if_have_a_different_permission()
{
Expand Down
15 changes: 15 additions & 0 deletions tests/RoleMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Gate;
use InvalidArgumentException;
use Spatie\Permission\Exceptions\UnauthorizedException;
use Spatie\Permission\Middlewares\RoleMiddleware;
use Spatie\Permission\Tests\TestModels\UserWithoutHasRoles;

class RoleMiddlewareTest extends TestCase
{
Expand Down Expand Up @@ -74,6 +76,19 @@ public function a_user_can_access_a_route_protected_by_this_role_middleware_if_h
);
}

/** @test */
public function a_user_cannot_access_a_route_protected_by_the_role_middleware_if_have_not_has_roles_trait()
{
$userWithoutHasRoles = UserWithoutHasRoles::create(['email' => 'test_not_has_roles@user.com']);

Auth::login($userWithoutHasRoles);

$this->assertEquals(
403,
$this->runMiddleware($this->roleMiddleware, 'testRole')
);
}

/** @test */
public function a_user_cannot_access_a_route_protected_by_the_role_middleware_if_have_a_different_role()
{
Expand Down
30 changes: 30 additions & 0 deletions tests/RoleOrPermissionMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Gate;
use InvalidArgumentException;
use Spatie\Permission\Exceptions\UnauthorizedException;
use Spatie\Permission\Middlewares\RoleOrPermissionMiddleware;
use Spatie\Permission\Tests\TestModels\UserWithoutHasRoles;

class RoleOrPermissionMiddlewareTest extends TestCase
{
Expand Down Expand Up @@ -64,6 +66,34 @@ public function a_user_can_access_a_route_protected_by_permission_or_role_middle
);
}

/** @test */
public function a_super_admin_user_can_access_a_route_protected_by_permission_or_role_middleware()
{
Auth::login($this->testUser);

Gate::before(function ($user, $ability) {
return $user->getKey() === $this->testUser->getKey() ? true : null;
});

$this->assertEquals(
200,
$this->runMiddleware($this->roleOrPermissionMiddleware, 'testRole|edit-articles')
);
}

/** @test */
public function a_user_can_not_access_a_route_protected_by_permission_or_role_middleware_if_have_not_has_roles_trait()
{
$userWithoutHasRoles = UserWithoutHasRoles::create(['email' => 'test_not_has_roles@user.com']);

Auth::login($userWithoutHasRoles);

$this->assertEquals(
403,
$this->runMiddleware($this->roleOrPermissionMiddleware, 'testRole|edit-articles')
);
}

/** @test */
public function a_user_can_not_access_a_route_protected_by_permission_or_role_middleware_if_have_not_this_permission_and_role()
{
Expand Down
21 changes: 21 additions & 0 deletions tests/TestModels/UserWithoutHasRoles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\Permission\Tests\TestModels;

use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;

class UserWithoutHasRoles extends Model implements AuthorizableContract, AuthenticatableContract
{
use Authorizable;
use Authenticatable;

protected $fillable = ['email'];

public $timestamps = false;

protected $table = 'users';
}

0 comments on commit eea8e15

Please sign in to comment.