Skip to content

Commit b83b328

Browse files
authored
Merge pull request #43 from Jurj-Bogdan/issue-42-for-v3
Allow route name placeholders
2 parents 5a11171 + 1e95d59 commit b83b328

File tree

9 files changed

+472
-38
lines changed

9 files changed

+472
-38
lines changed

docs/book/v3/configuration.md

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
As with many Dotkernel modules, we focus on the configuration based approach of customizing the module for your needs.
44

5-
After installing, merge the module's `ConfigProvider` with your application's config to make sure required dependencies and default module configuration are registered. Create a configuration file for this module in your 'config/autoload' folder.
5+
After installing, merge the module's `ConfigProvider` with your application's config to make sure required dependencies and default module configuration are registered.
6+
Create a configuration file for this module in your 'config/autoload' folder.
67

78
## authorization-guards.global.php
89

@@ -41,8 +42,8 @@ return [
4142
'logout' => ['admin', 'user', 'viewer'],
4243
'account' => ['admin', 'user'],
4344
'home' => ['*'],
44-
]
45-
]
45+
],
46+
],
4647
],
4748
[
4849
'type' => 'RoutePermission',
@@ -51,40 +52,40 @@ return [
5152
'premium' => ['premium'],
5253
'account' => ['my-account'],
5354
'logout' => ['only-logged'],
54-
]
55-
]
55+
],
56+
],
5657
],
5758
[
5859
'type' => 'Controller',
5960
'options' => [
6061
'rules' => [
6162
[
6263
'route' => 'controller route name',
63-
'actions' => [//list of actions to apply, or empty array for all actions],
64-
//by default, authorization pass if all permissions are present(AND)
65-
'roles' => [//list of roles to allow],
64+
'actions' => [], //list of actions to apply, or empty array for all actions,
65+
// by default, authorization passes if all permissions are present(AND)
66+
'roles' => ['admin'], //list of roles to allow,
6667
],
67-
]
68-
]
68+
],
69+
],
6970
],
7071
[
7172
'type' => 'ControllerPermission',
7273
'options' => [
7374
'rules' => [
7475
[
7576
'route' => 'controller route name',
76-
'actions' => [//list of actions to apply, or empty array for all actions],
77-
//by default, authorization pass if all permissions are present(AND)
78-
'permissions' => [//list of permissions to allow],
77+
'actions' => [], //list of actions to apply, or empty array for all actions,
78+
// by default, authorization passes if all permissions are present(AND)
79+
'permissions' => ['authenticated'], //list of permissions to allow,
7980
],
8081
[
8182
'route' => 'controller route name',
82-
'actions' => [//list of actions to apply, or empty array for all actions],
83+
'actions' => [], //list of actions to apply, or empty array for all actions,
8384
'permissions' => [
8485
//permission can be defined in this way too, for all permission type guards
85-
'permissions' => [//list of permissions],
86+
'permissions' => ['authenticated'], //list of permissions,
8687
'condition' => \Dot\Rbac\Guard\GuardInterface::CONDITION_OR,
87-
]
88+
],
8889
]
8990
]
9091
]
@@ -103,3 +104,71 @@ return [
103104
],
104105
];
105106
```
107+
108+
> It is **strongly recommended** to explicitly define permissions or roles and not leave the values empty, especially if using `GuardInterface::POLICY_DENY`!
109+
110+
## Route Name Placeholders
111+
112+
Route **names** are allowed to contain `*` as placeholders, allowing more compact specifications.
113+
This feature is available for all types of guards.
114+
115+
> Note that route rules are verified in order of their writing, take care of the order when using placeholder routes, as not to overwrite any specific routes!
116+
117+
```php
118+
[
119+
'type' => 'Route',
120+
'options' => [
121+
'rules' => [
122+
'account-create-form' => ['admin'],
123+
'account-update-form' => ['admin'],
124+
'account-delete-form' => ['admin'],
125+
]
126+
],
127+
[
128+
'type' => 'Controller',
129+
'options' => [
130+
'rules' => [
131+
[
132+
'route' => 'admin-create',
133+
'actions' => [],
134+
'roles' => ['admin'],
135+
],
136+
[
137+
'route' => 'admin-edit',
138+
'actions' => [],
139+
'roles' => ['admin'],
140+
],
141+
[
142+
'route' => 'admin-view',
143+
'actions' => [],
144+
'roles' => ['admin'],
145+
],
146+
]
147+
]
148+
],
149+
],
150+
151+
152+
// Can be written as:
153+
154+
[
155+
'type' => 'Route',
156+
'options' => [
157+
'rules' => [
158+
'account-*-form' => ['admin'],
159+
]
160+
],
161+
[
162+
'type' => 'Controller',
163+
'options' => [
164+
'rules' => [
165+
[
166+
'route' => 'admin-*',
167+
'actions' => [],
168+
'roles' => ['admin'],
169+
],
170+
]
171+
]
172+
],
173+
]
174+
```

src/Guard/ControllerGuard.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
use Mezzio\Router\RouteResult;
1111
use Psr\Http\Message\ServerRequestInterface;
1212

13+
use function array_keys;
1314
use function in_array;
15+
use function preg_match;
16+
use function sprintf;
17+
use function str_contains;
18+
use function str_replace;
1419
use function strtolower;
1520

1621
class ControllerGuard extends AbstractGuard
@@ -19,6 +24,8 @@ class ControllerGuard extends AbstractGuard
1924

2025
protected ?RoleServiceInterface $roleService = null;
2126

27+
protected array $rules = [];
28+
2229
public function __construct(?array $options = null)
2330
{
2431
$options = $options ?? [];
@@ -34,8 +41,6 @@ public function __construct(?array $options = null)
3441

3542
public function setRules(array $rules): void
3643
{
37-
$this->rules = [];
38-
3944
foreach ($rules as $rule) {
4045
$route = strtolower($rule['route']);
4146
$actions = isset($rule['actions']) ? (array) $rule['actions'] : [];
@@ -72,6 +77,22 @@ public function isGranted(ServerRequestInterface $request): bool
7277

7378
$route = strtolower($routeResult->getMatchedRouteName());
7479

80+
foreach (array_keys($this->rules) as $routeName) {
81+
if (str_contains($routeName, '*')) {
82+
$routePattern = sprintf(
83+
"/^%s$/",
84+
str_replace('*', '[\w\-]+', $routeName)
85+
);
86+
87+
$routeMatched = preg_match($routePattern, $route);
88+
89+
if ($routeMatched === 1) {
90+
$route = $routeName;
91+
break;
92+
}
93+
}
94+
}
95+
7596
if (! isset($this->rules[$route])) {
7697
return $this->protectionPolicy === self::POLICY_ALLOW;
7798
}

src/Guard/ControllerPermissionGuard.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@
1111
use Mezzio\Router\RouteResult;
1212
use Psr\Http\Message\ServerRequestInterface;
1313

14+
use function array_keys;
1415
use function gettype;
1516
use function in_array;
1617
use function is_object;
18+
use function preg_match;
1719
use function sprintf;
20+
use function str_contains;
21+
use function str_replace;
1822
use function strtolower;
1923

2024
class ControllerPermissionGuard extends AbstractGuard
@@ -23,6 +27,8 @@ class ControllerPermissionGuard extends AbstractGuard
2327

2428
protected ?AuthorizationInterface $authorizationService = null;
2529

30+
protected array $rules = [];
31+
2632
public function __construct(?array $options = null)
2733
{
2834
$options = $options ?? [];
@@ -42,8 +48,6 @@ public function __construct(?array $options = null)
4248

4349
public function setRules(array $rules): void
4450
{
45-
$this->rules = [];
46-
4751
foreach ($rules as $rule) {
4852
$route = strtolower($rule['route']);
4953
$actions = isset($rule['actions']) ? (array) $rule['actions'] : [];
@@ -69,6 +73,23 @@ public function isGranted(ServerRequestInterface $request): bool
6973
}
7074

7175
$route = $routeResult->getMatchedRouteName();
76+
77+
foreach (array_keys($this->rules) as $routeName) {
78+
if (str_contains($routeName, '*')) {
79+
$routePattern = sprintf(
80+
"/^%s$/",
81+
str_replace('*', '[\w\-]+', $routeName)
82+
);
83+
84+
$routeMatched = preg_match($routePattern, $route);
85+
86+
if ($routeMatched === 1) {
87+
$route = $routeName;
88+
break;
89+
}
90+
}
91+
}
92+
7293
if (! isset($this->rules[$route])) {
7394
return $this->protectionPolicy === self::POLICY_ALLOW;
7495
}

src/Guard/RouteGuard.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
use function array_keys;
1313
use function in_array;
1414
use function is_int;
15+
use function preg_match;
16+
use function sprintf;
17+
use function str_contains;
18+
use function str_replace;
1519
use function strtolower;
1620

1721
class RouteGuard extends AbstractGuard
@@ -20,6 +24,8 @@ class RouteGuard extends AbstractGuard
2024

2125
protected ?RoleServiceInterface $roleService = null;
2226

27+
protected array $rules = [];
28+
2329
public function __construct(?array $options = null)
2430
{
2531
$options = $options ?? [];
@@ -36,8 +42,6 @@ public function __construct(?array $options = null)
3642

3743
public function setRules(array $rules): void
3844
{
39-
$this->rules = [];
40-
4145
foreach ($rules as $key => $value) {
4246
if (is_int($key)) {
4347
$routeName = strtolower($value);
@@ -73,9 +77,23 @@ public function isGranted(ServerRequestInterface $request): bool
7377
$allowedRoles = null;
7478

7579
foreach (array_keys($this->rules) as $routeName) {
76-
if ($routeName === $matchedRouteName) {
77-
$allowedRoles = $this->rules[$routeName];
78-
break;
80+
if (str_contains($routeName, '*')) {
81+
$routePattern = sprintf(
82+
"/^%s$/",
83+
str_replace('*', '[\w\-]+', $routeName)
84+
);
85+
86+
$routeMatched = preg_match($routePattern, $matchedRouteName);
87+
88+
if ($routeMatched === 1) {
89+
$allowedRoles = $this->rules[$routeName];
90+
break;
91+
}
92+
} else {
93+
if ($routeName === $matchedRouteName) {
94+
$allowedRoles = $this->rules[$routeName];
95+
break;
96+
}
7997
}
8098
}
8199

src/Guard/RoutePermissionGuard.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
use function in_array;
1616
use function is_int;
1717
use function is_object;
18+
use function preg_match;
1819
use function sprintf;
20+
use function str_contains;
21+
use function str_replace;
1922
use function strtolower;
2023

2124
class RoutePermissionGuard extends AbstractGuard
@@ -24,6 +27,8 @@ class RoutePermissionGuard extends AbstractGuard
2427

2528
protected ?AuthorizationInterface $authorizationService = null;
2629

30+
protected array $rules = [];
31+
2732
public function __construct(?array $options = null)
2833
{
2934
$options = $options ?? [];
@@ -43,7 +48,6 @@ public function __construct(?array $options = null)
4348

4449
public function setRules(array $rules): void
4550
{
46-
$this->rules = [];
4751
foreach ($rules as $key => $value) {
4852
if (is_int($key)) {
4953
$routeName = strtolower($value);
@@ -68,9 +72,23 @@ public function isGranted(ServerRequestInterface $request): bool
6872
$allowedPermissions = null;
6973

7074
foreach (array_keys($this->rules) as $routeName) {
71-
if ($matchedRouteName === $routeName) {
72-
$allowedPermissions = $this->rules[$routeName];
73-
break;
75+
if (str_contains($routeName, '*')) {
76+
$routePattern = sprintf(
77+
"/^%s$/",
78+
str_replace('*', '[\w\-]+', $routeName)
79+
);
80+
81+
$routeMatched = preg_match($routePattern, $matchedRouteName);
82+
83+
if ($routeMatched === 1) {
84+
$allowedPermissions = $this->rules[$routeName];
85+
break;
86+
}
87+
} else {
88+
if ($matchedRouteName === $routeName) {
89+
$allowedPermissions = $this->rules[$routeName];
90+
break;
91+
}
7492
}
7593
}
7694

0 commit comments

Comments
 (0)