Skip to content

Commit f334a92

Browse files
authored
Merge pull request #791 from sammyskills/support-multiple-permissions
feat: add support for multiple permissions check for users
2 parents 78cac54 + 6d9e5be commit f334a92

File tree

3 files changed

+63
-31
lines changed

3 files changed

+63
-31
lines changed

docs/authorization.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,19 @@ The `Authorizable` trait on the `User` entity provides the following methods to
111111

112112
#### can()
113113

114-
Allows you to check if a user is permitted to do a specific action. The only argument is the permission string. Returns
114+
Allows you to check if a user is permitted to do a specific action or group or actions. The permission string(s) should be passed as the argument(s). Returns
115115
boolean `true`/`false`. Will check the user's direct permissions (**user-level permissions**) first, and then check against all of the user's groups
116116
permissions (**group-level permissions**) to determine if they are allowed.
117117

118118
```php
119119
if ($user->can('users.create')) {
120120
//
121121
}
122+
123+
// If multiple permissions are specified, true is returned if the user has any of them.
124+
if ($user->can('users.create', 'users.edit')) {
125+
//
126+
}
122127
```
123128

124129
#### inGroup()

src/Authorization/Traits/Authorizable.php

+35-30
Original file line numberDiff line numberDiff line change
@@ -226,49 +226,54 @@ public function hasPermission(string $permission): bool
226226

227227
/**
228228
* Checks user permissions and their group permissions
229-
* to see if the user has a specific permission.
229+
* to see if the user has a specific permission or group
230+
* of permissions.
230231
*
231-
* @param string $permission string consisting of a scope and action, like `users.create`
232+
* @param string $permissions string(s) consisting of a scope and action, like `users.create`
232233
*/
233-
public function can(string $permission): bool
234+
public function can(string ...$permissions): bool
234235
{
235-
if (strpos($permission, '.') === false) {
236-
throw new LogicException(
237-
'A permission must be a string consisting of a scope and action, like `users.create`.'
238-
. ' Invalid permission: ' . $permission
239-
);
240-
}
241-
236+
// Get user's permissions and store in cache
242237
$this->populatePermissions();
243238

244-
$permission = strtolower($permission);
245-
246-
// Check user's permissions
247-
if (in_array($permission, $this->permissionsCache, true)) {
248-
return true;
249-
}
250-
251239
// Check the groups the user belongs to
252240
$this->populateGroups();
253241

254-
if (! count($this->groupCache)) {
255-
return false;
256-
}
242+
foreach ($permissions as $permission) {
243+
// Permission must contain a scope and action
244+
if (strpos($permission, '.') === false) {
245+
throw new LogicException(
246+
'A permission must be a string consisting of a scope and action, like `users.create`.'
247+
. ' Invalid permission: ' . $permission
248+
);
249+
}
257250

258-
$matrix = function_exists('setting')
259-
? setting('AuthGroups.matrix')
260-
: config('AuthGroups')->matrix;
251+
$permission = strtolower($permission);
261252

262-
foreach ($this->groupCache as $group) {
263-
// Check exact match
264-
if (isset($matrix[$group]) && in_array($permission, $matrix[$group], true)) {
253+
// Check user's permissions
254+
if (in_array($permission, $this->permissionsCache, true)) {
265255
return true;
266256
}
267257

268-
// Check wildcard match
269-
$check = substr($permission, 0, strpos($permission, '.')) . '.*';
270-
if (isset($matrix[$group]) && in_array($check, $matrix[$group], true)) {
271-
return true;
258+
if (! count($this->groupCache)) {
259+
return false;
260+
}
261+
262+
$matrix = function_exists('setting')
263+
? setting('AuthGroups.matrix')
264+
: config('AuthGroups')->matrix;
265+
266+
foreach ($this->groupCache as $group) {
267+
// Check exact match
268+
if (isset($matrix[$group]) && in_array($permission, $matrix[$group], true)) {
269+
return true;
270+
}
271+
272+
// Check wildcard match
273+
$check = substr($permission, 0, strpos($permission, '.')) . '.*';
274+
if (isset($matrix[$group]) && in_array($check, $matrix[$group], true)) {
275+
return true;
276+
}
272277
}
273278
}
274279

tests/Authorization/AuthorizableTest.php

+22
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,28 @@ public function testCanGetsInvalidPermission(): void
305305
$this->assertTrue($this->user->can('developer'));
306306
}
307307

308+
/**
309+
* @see https://github.com/codeigniter4/shield/pull/791#discussion_r1297712860
310+
*/
311+
public function testCanWorksWithMultiplePermissions(): void
312+
{
313+
// Check for user's direct permissions (user-level permissions)
314+
$this->user->addPermission('users.create', 'users.edit');
315+
316+
$this->assertTrue($this->user->can('users.create', 'users.edit'));
317+
$this->assertFalse($this->user->can('beta.access', 'admin.access'));
318+
319+
$this->user->removePermission('users.create', 'users.edit');
320+
321+
$this->assertFalse($this->user->can('users.edit', 'users.create'));
322+
323+
// Check for user's group permissions (group-level permissions)
324+
$this->user->addGroup('superadmin');
325+
326+
$this->assertTrue($this->user->can('admin.access', 'beta.access'));
327+
$this->assertTrue($this->user->can('admin.*', 'users.*'));
328+
}
329+
308330
/**
309331
* @see https://github.com/codeigniter4/shield/pull/238
310332
*/

0 commit comments

Comments
 (0)