Skip to content

Commit c35458e

Browse files
author
igor-chepurnoi
committed
improve AccessControl filter, add allowActions property
1 parent aad914d commit c35458e

File tree

4 files changed

+114
-26
lines changed

4 files changed

+114
-26
lines changed

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ class ExampleController extends Controller
101101
return [
102102
'access' => [
103103
'class' => AccessControl::class,
104+
'allowActions' => [
105+
'index',
106+
// The actions listed here will be allowed to everyone including guests.
107+
]
104108
],
105109
];
106110
}
@@ -130,6 +134,8 @@ class Module extends \yii\base\Module
130134
```
131135
3) Also you can apply rules via main configuration:
132136
```php
137+
// apply for single module
138+
133139
'modules' => [
134140
'rbac' => [
135141
'class' => 'yii2mod\rbac\Module',
@@ -138,6 +144,28 @@ class Module extends \yii\base\Module
138144
],
139145
]
140146
]
147+
148+
// or apply globally for whole application
149+
150+
'modules' => [
151+
...
152+
],
153+
'components' => [
154+
...
155+
],
156+
'as access' => [
157+
'class' => yii2mod\rbac\filters\AccessControl::class,
158+
'allowActions' => [
159+
'site/*',
160+
'admin/*',
161+
// The actions listed here will be allowed to everyone including guests.
162+
// So, 'admin/*' should not appear here in the production, of course.
163+
// But in the earlier stages of your development, you may probably want to
164+
// add a lot of actions here until you finally completed setting up rbac,
165+
// otherwise you may not even take a first step.
166+
]
167+
],
168+
141169
```
142170

143171
## Internationalization

filters/AccessControl.php

+82-22
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace yii2mod\rbac\filters;
44

55
use Yii;
6-
use yii\base\InlineAction;
6+
use yii\base\Action;
7+
use yii\base\Module;
8+
use yii\helpers\ArrayHelper;
9+
use yii\helpers\Url;
710

811
/**
912
* Class AccessControl
@@ -17,25 +20,24 @@ class AccessControl extends \yii\filters\AccessControl
1720
public $params = [];
1821

1922
/**
20-
* This method is invoked right before an action is to be executed (after all possible filters.)
21-
*
22-
* @param InlineAction $action the action to be executed.
23-
* @return boolean whether the action should continue to be executed.
23+
* @var array list of action that not need to check access.
24+
*/
25+
public $allowActions = [];
26+
27+
/**
28+
* @inheritdoc
2429
*/
2530
public function beforeAction($action)
2631
{
27-
$actionId = $action->getUniqueId();
28-
$user = Yii::$app->getUser();
29-
$params = isset($this->params[$action->id]) ? $this->params[$action->id] : [];
32+
$controller = $action->controller;
33+
$params = ArrayHelper::getValue($this->params, $action->id, []);
3034

31-
if ($user->can('/' . $actionId, $params)) {
35+
if (Yii::$app->user->can('/' . $action->getUniqueId(), $params)) {
3236
return true;
3337
}
3438

35-
$controller = $action->controller;
36-
3739
do {
38-
if ($user->can('/' . ltrim($controller->getUniqueId() . '/*', '/'))) {
40+
if (Yii::$app->user->can('/' . ltrim($controller->getUniqueId() . '/*', '/'))) {
3941
return true;
4042
}
4143
$controller = $controller->module;
@@ -44,23 +46,81 @@ public function beforeAction($action)
4446
return parent::beforeAction($action);
4547
}
4648

47-
4849
/**
49-
* Returns a value indicating whether the filer is active for the given action.
50-
*
51-
* @param InlineAction $action the action being filtered
52-
* @return boolean whether the filer is active for the given action.
50+
* @inheritdoc
5351
*/
5452
protected function isActive($action)
5553
{
56-
$uniqueId = $action->getUniqueId();
57-
58-
if ($uniqueId === Yii::$app->getErrorHandler()->errorAction) {
59-
return false;
60-
} else if (Yii::$app->user->isGuest && Yii::$app->user->loginUrl == $uniqueId) {
54+
if ($this->isErrorPage($action) || $this->isLoginPage($action) || $this->isAllowedAction($action)) {
6155
return false;
6256
}
6357

6458
return parent::isActive($action);
6559
}
60+
61+
/**
62+
* Returns a value indicating whether a current url equals `errorAction` property of the ErrorHandler component
63+
*
64+
* @param Action $action
65+
* @return bool
66+
*/
67+
private function isErrorPage($action)
68+
{
69+
if ($action->getUniqueId() === Yii::$app->getErrorHandler()->errorAction) {
70+
return true;
71+
}
72+
73+
return false;
74+
}
75+
76+
/**
77+
* Returns a value indicating whether a current url equals `loginUrl` property of the User component
78+
*
79+
* @param Action $action
80+
* @return bool
81+
*/
82+
private function isLoginPage($action)
83+
{
84+
$loginUrl = trim(Url::to(Yii::$app->user->loginUrl), '/');
85+
86+
if (Yii::$app->user->isGuest && $action->getUniqueId() === $loginUrl) {
87+
return true;
88+
}
89+
90+
return false;
91+
}
92+
93+
/**
94+
* Returns a value indicating whether a current url exists in the `allowActions` list.
95+
*
96+
* @param Action $action
97+
* @return bool
98+
*/
99+
private function isAllowedAction($action)
100+
{
101+
if ($this->owner instanceof Module) {
102+
$ownerId = $this->owner->getUniqueId();
103+
$id = $action->getUniqueId();
104+
if (!empty($ownerId) && strpos($id, $ownerId . '/') === 0) {
105+
$id = substr($id, strlen($ownerId) + 1);
106+
}
107+
} else {
108+
$id = $action->id;
109+
}
110+
111+
foreach ($this->allowActions as $route) {
112+
if (substr($route, -1) === '*') {
113+
$route = rtrim($route, "*");
114+
if ($route === '' || strpos($id, $route) === 0) {
115+
return true;
116+
}
117+
} else {
118+
if ($id === $route) {
119+
return true;
120+
}
121+
}
122+
}
123+
124+
return false;
125+
}
66126
}

tests/models/BizRuleTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ class BizRuleTest extends TestCase
1616
{
1717
public function testCreateRule()
1818
{
19-
$model = new BizRuleModel(null);
19+
$model = new BizRuleModel;
2020
$model->name = 'guest';
2121
$model->className = GuestRule::className();
2222

2323
$this->assertTrue($model->save());
2424

2525
$rule = Yii::$app->authManager->getRule($model->name);
2626
$this->assertInstanceOf(Rule::className(), $rule);
27-
27+
2828
return $rule;
2929
}
3030

tests/models/RoleTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ class RoleTest extends TestCase
1616
{
1717
public function testCreateRole()
1818
{
19-
$model = new AuthItemModel(null);
19+
$model = new AuthItemModel;
2020
$model->type = Item::TYPE_ROLE;
2121
$model->name = 'admin';
2222
$model->description = 'admin role';
2323

2424
$this->assertTrue($model->save());
2525
$this->assertInstanceOf(Role::className(), Yii::$app->authManager->getRole('admin'));
26-
26+
2727
return Yii::$app->authManager->getRole('admin');
2828
}
2929

0 commit comments

Comments
 (0)