1
|
|
|
<?php /** AccessFilterMicro */ |
2
|
|
|
|
3
|
|
|
namespace Micro\Filter; |
4
|
|
|
|
5
|
|
|
use Micro\Base\Exception; |
6
|
|
|
use Micro\Web\IUser; |
7
|
|
|
use Micro\Web\RequestInjector; |
8
|
|
|
use Micro\Web\UserInjector; |
9
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class AccessFilter |
13
|
|
|
* |
14
|
|
|
* @author Oleg Lunegov <[email protected]> |
15
|
|
|
* @link https://github.com/linpax/microphp-framework |
16
|
|
|
* @copyright Copyright (c) 2013 Oleg Lunegov |
17
|
|
|
* @license https://github.com/linpax/microphp-framework/blob/master/LICENSE |
18
|
|
|
* @package Micro |
19
|
|
|
* @subpackage Filter |
20
|
|
|
* @version 1.0 |
21
|
|
|
* @since 1.0 |
22
|
|
|
*/ |
23
|
|
|
class AccessFilter extends Filter |
24
|
|
|
{ |
25
|
|
|
/** @var IUser $user */ |
26
|
|
|
protected $user; |
27
|
|
|
/** @var ServerRequestInterface $request */ |
28
|
|
|
protected $request; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @param array $params |
32
|
|
|
* @return bool |
33
|
|
|
* @throws Exception |
34
|
|
|
*/ |
35
|
|
|
public function pre(array $params) |
36
|
|
|
{ |
37
|
|
|
$this->user = (new UserInjector)->build(); |
38
|
|
|
$this->request = (new RequestInjector)->build(); |
39
|
|
|
|
40
|
|
|
/** @noinspection ForeachSourceInspection */ |
41
|
|
|
foreach ($params['rules'] AS $rule) { |
42
|
|
|
$res = $this->checkRule($rule); |
43
|
|
|
|
44
|
|
|
if ($res === true) { |
45
|
|
|
return true; |
46
|
|
View Code Duplication |
} elseif ($res === false) { |
|
|
|
|
47
|
|
|
$this->result = [ |
48
|
|
|
'redirect' => !empty($rule['redirect']) ? $rule['redirect'] : null, |
49
|
|
|
'message' => !empty($rule['message']) ? $rule['message'] : 'Access denied!' |
50
|
|
|
]; |
51
|
|
|
|
52
|
|
|
return false; |
53
|
|
|
} elseif ($res === null) { |
54
|
|
|
continue; |
55
|
|
|
} |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
return true; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Check one rule |
63
|
|
|
* |
64
|
|
|
* @access protected |
65
|
|
|
* |
66
|
|
|
* @param array $rule rule definition |
67
|
|
|
* |
68
|
|
|
* @return bool|null |
69
|
|
|
* @throws Exception |
70
|
|
|
*/ |
71
|
|
|
protected function checkRule(array $rule) |
72
|
|
|
{ |
73
|
|
|
if ( |
74
|
|
|
$this->matchAction($rule) |
75
|
|
|
&& $this->matchUser($rule) |
76
|
|
|
&& $this->matchRole($rule) |
77
|
|
|
&& $this->matchIP($rule) |
78
|
|
|
&& $this->matchVerb($rule) |
79
|
|
|
) { |
80
|
|
|
return $rule['allow']; |
81
|
|
|
} else { |
82
|
|
|
return null; |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Match action |
88
|
|
|
* |
89
|
|
|
* @access protected |
90
|
|
|
* |
91
|
|
|
* @param array $rule rule definition |
92
|
|
|
* |
93
|
|
|
* @return bool |
94
|
|
|
*/ |
95
|
|
|
protected function matchAction($rule) |
96
|
|
|
{ |
97
|
|
|
if (empty($rule['actions'])) { |
98
|
|
|
return true; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
if (is_array($rule['actions'])) { |
102
|
|
|
return in_array($this->action, $rule['actions'], true); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
return $this->action === $rule['actions']; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Match user |
110
|
|
|
* |
111
|
|
|
* @access protected |
112
|
|
|
* |
113
|
|
|
* @param array $rule rule definition |
114
|
|
|
* |
115
|
|
|
* @return bool |
116
|
|
|
* @throws Exception |
117
|
|
|
*/ |
118
|
|
|
protected function matchUser($rule) |
119
|
|
|
{ |
120
|
|
|
if (empty($rule['users'])) { |
121
|
|
|
return true; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
if (!is_array($rule['users'])) { |
125
|
|
|
$rule['users'][] = $rule['users']; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** @noinspection ForeachSourceInspection */ |
129
|
|
|
foreach ($rule['users'] AS $u) { |
130
|
|
|
switch ($u) { |
131
|
|
|
case '*': |
132
|
|
|
return true; |
133
|
|
|
|
134
|
|
|
case '?': |
135
|
|
|
if ($this->user->isGuest()) { |
136
|
|
|
return true; |
137
|
|
|
} |
138
|
|
|
break; |
139
|
|
|
|
140
|
|
|
case '@': |
141
|
|
|
if (!$this->user->isGuest()) { |
142
|
|
|
return true; |
143
|
|
|
} |
144
|
|
|
break; |
145
|
|
|
|
146
|
|
|
default: |
147
|
|
|
if ($this->user->getID() === $u) { |
148
|
|
|
return true; |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return false; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Match role |
158
|
|
|
* |
159
|
|
|
* @access protected |
160
|
|
|
* |
161
|
|
|
* @param array $rule rule definition |
162
|
|
|
* |
163
|
|
|
* @return bool |
164
|
|
|
* @throws Exception |
165
|
|
|
*/ |
166
|
|
View Code Duplication |
protected function matchRole($rule) |
|
|
|
|
167
|
|
|
{ |
168
|
|
|
if (empty($rule['roles'])) { |
169
|
|
|
return true; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if (!is_array($rule['roles'])) { |
173
|
|
|
$rule['roles'][] = $rule['roles']; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** @noinspection ForeachSourceInspection */ |
177
|
|
|
foreach ($rule['roles'] AS $role) { |
178
|
|
|
if ($this->user->check($role)) { |
179
|
|
|
return true; |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
return false; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* Match IP |
188
|
|
|
* |
189
|
|
|
* @access protected |
190
|
|
|
* |
191
|
|
|
* @param array $rule rule definition |
192
|
|
|
* |
193
|
|
|
* @return bool |
194
|
|
|
* @throws Exception |
195
|
|
|
*/ |
196
|
|
|
protected function matchIP($rule) |
197
|
|
|
{ |
198
|
|
|
if (empty($rule['ips'])) { |
199
|
|
|
return true; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
if (!is_array($rule['ips'])) { |
203
|
|
|
$rule['ips'][] = $rule['ips']; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
$server = $this->request->getServerParams(); |
207
|
|
|
$userIp = ($ip = filter_var($server['REMOTE_ADDR'], FILTER_VALIDATE_IP)) ? $ip : '127.0.0.1'; |
208
|
|
|
|
209
|
|
|
/** @noinspection ForeachSourceInspection */ |
210
|
|
|
foreach ($rule['ips'] AS $r) { |
211
|
|
|
if ($r === '*' || $r === $userIp || (($pos = strpos($r, '*')) !== false && 0 === strpos($userIp, $r))) { |
212
|
|
|
return true; |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
return false; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Match verbose |
221
|
|
|
* |
222
|
|
|
* @access protected |
223
|
|
|
* |
224
|
|
|
* @param array $rule rule definition |
225
|
|
|
* |
226
|
|
|
* @return bool |
227
|
|
|
* @throws Exception |
228
|
|
|
*/ |
229
|
|
View Code Duplication |
protected function matchVerb($rule) |
|
|
|
|
230
|
|
|
{ |
231
|
|
|
if (empty($rule['verb'])) { |
232
|
|
|
return true; |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
if (!is_array($rule['verb'])) { |
236
|
|
|
$rule['verb'][] = $rule['verb']; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
$verb = $this->request->getMethod(); |
240
|
|
|
|
241
|
|
|
/** @noinspection ForeachSourceInspection */ |
242
|
|
|
foreach ($rule['verb'] AS $v) { |
243
|
|
|
if ($v === $verb) { |
244
|
|
|
return true; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
return false; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* @inheritdoc |
253
|
|
|
*/ |
254
|
|
|
public function post(array $params) |
255
|
|
|
{ |
256
|
|
|
return $params['data']; |
257
|
|
|
} |
258
|
|
|
} |
259
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.