Skip to content

Commit 4974570

Browse files
committed
try to implement FilterAdapter
1 parent e0355bd commit 4974570

File tree

3 files changed

+258
-0
lines changed

3 files changed

+258
-0
lines changed

.DS_Store

8 KB
Binary file not shown.

index.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
require_once './vendor/autoload.php';
3+
4+
use Casbin\Enforcer;
5+
use Casbin\Persist\Adapters\Filter;
6+
use Casbin\Util\Log;
7+
use CasbinAdapter\Database\FilterAdapter as FilterDatabaseAdapter;
8+
use Casbin\Exceptions\InvalidFilterTypeException;
9+
use Casbin\Model\Model;
10+
11+
$config = [
12+
'type' => 'mysql', // mysql,pgsql,sqlite,sqlsrv
13+
'hostname' => '127.0.0.1',
14+
'database' => 'weibo',
15+
'username' => 'homestead',
16+
'password' => 'secret',
17+
'hostport' => '3306',
18+
];
19+
$model = Model::newModelFromFile('./tests/rbac_model.conf');
20+
21+
$adapter = FilterDatabaseAdapter::newAdapter($config);
22+
23+
//$e = new Enforcer('./model.conf', $adapter);
24+
$e = new Enforcer($model, $adapter);
25+
26+
$sub = "alice"; // the user that wants to access a resource.
27+
$obj = "data1"; // the resource that is going to be accessed.
28+
$act = "read"; // the operation that the user performs on the resource.
29+
//$e->addPolicy('alice', 'data12', 'read');exit;
30+
try {
31+
$filter = new Filter(['alice']);
32+
$e->loadFilteredPolicy($filter);
33+
var_dump($model['p']['p']->policy);
34+
} catch (InvalidFilterTypeException $e) {
35+
echo $e->getMessage();
36+
}

src/FilterAdapter.php

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<?php
2+
3+
namespace CasbinAdapter\Database;
4+
5+
use Casbin\Model\Model;
6+
use Casbin\Persist\Adapters\Filter;
7+
use Casbin\Exceptions\InvalidFilterTypeException;
8+
use Casbin\Persist\FilteredAdapter;
9+
10+
/**
11+
* DatabaseAdapter.
12+
*
13+
14+
*/
15+
class FilterAdapter extends Adapter implements FilteredAdapter
16+
{
17+
/**
18+
* filtered variable.
19+
*
20+
* @var bool
21+
*/
22+
protected $filtered;
23+
24+
public function __construct(array $config)
25+
{
26+
$this->filtered = true;
27+
parent::__construct($config);
28+
}
29+
30+
/**
31+
* Returns true if the loaded policy has been filtered.
32+
*
33+
* @return bool
34+
*/
35+
public function isFiltered(): bool
36+
{
37+
return $this->filtered;
38+
}
39+
40+
/**
41+
* Loads only policy rules that match the filter from storage.
42+
*
43+
* @param Model $model
44+
* @param mixed $filter
45+
*
46+
* @throws CasbinException
47+
*/
48+
public function loadFilteredPolicy(Model $model, $filter): void
49+
{
50+
// 如果$filter为空,就加载所有的策略
51+
if (is_null($filter)) {
52+
$this->loadPolicy($model);
53+
return;
54+
}
55+
// 确保$filter的类型正确
56+
if (!$filter instanceof Filter) {
57+
throw new InvalidFilterTypeException('invalid filter type');
58+
}
59+
$type = '';
60+
$filter = (array) $filter;
61+
// 要判断ptype是p还是g
62+
foreach($filter as $i => $v) {
63+
if (!empty($v)) {
64+
array_unshift($filter[$i], $i);
65+
$type = $i;
66+
break;
67+
}
68+
}
69+
$sql = 'SELECT ptype, v0, v1, v2, v3, v4, v5 FROM '.$this->casbinRuleTableName . ' WHERE ';
70+
$items = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
71+
$temp = [];
72+
$values = [];
73+
foreach($items as $i => $item) {
74+
if (isset($filter[$type][$i]) && !empty($filter[$type][$i])) {
75+
array_push($temp, $item . '=:' . $item);
76+
$values[$item] = $filter[$type][$i];
77+
}
78+
}
79+
$sql .= implode(' and ', $temp);
80+
$rows = $this->connection->query($sql, $values);
81+
foreach($rows as $row) {
82+
$line = implode(', ', $row);
83+
$this->loadPolicyLine($line, $model);
84+
}
85+
86+
$this->filtered = true;
87+
}
88+
89+
/**
90+
* load filtered policy
91+
* 通过拼接sql语句来实现过滤功能,但直接将字段的值进行了拼接,存在安全方面的问题,无法防止SQL注入等情况,应该用query方法的第二个参数来改写
92+
*
93+
* @param Model $model
94+
* @param [type] $filter
95+
* @return void
96+
*/
97+
public function loadFilteredPolicy1(Model $model, $filter): void
98+
{
99+
// 如果$filter为空,就加载所有的策略
100+
if (is_null($filter)) {
101+
$this->loadPolicy($model);
102+
return;
103+
}
104+
// 确保$filter的类型正确
105+
if (!$filter instanceof Filter) {
106+
throw new InvalidFilterTypeException('invalid filter type');
107+
}
108+
$filter = (array) $filter;
109+
// 要判断ptype是p还是g
110+
foreach($filter as $i => $v) {
111+
if (!empty($v)) {
112+
array_unshift($filter[$i], $i);
113+
break;
114+
}
115+
}
116+
$sql = 'SELECT ptype, v0, v1, v2, v3, v4, v5 FROM '.$this->casbinRuleTableName . ' WHERE ';
117+
$items = ['ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5'];
118+
$temp = [];
119+
foreach($items as $i => $item) {
120+
if (isset($filter['p'][$i]) && !empty($filter['p'][$i])) {
121+
array_push($temp, $item . '=' . '\'' . $filter['p'][$i] . '\'');
122+
}
123+
}
124+
$sql .= implode(' and ', $temp);
125+
$rows = $this->connection->query($sql);
126+
foreach($rows as $row) {
127+
$line = implode(', ', $row);
128+
$this->loadPolicyLine($line, $model);
129+
}
130+
$this->filtered = true;
131+
}
132+
133+
/**
134+
* load filtered policy
135+
* 仿照文件过滤适配器完成的,代码较多
136+
*
137+
* @param Model $model
138+
* @param [type] $filter
139+
* @return void
140+
*/
141+
public function loadFilteredPolicy2(Model $model, $filter): void
142+
{
143+
// 如果$filter为空,就加载所有的策略
144+
if (is_null($filter)) {
145+
$this->loadPolicy($model);
146+
return;
147+
}
148+
// 确保$filter的类型正确
149+
if (!$filter instanceof Filter) {
150+
throw new InvalidFilterTypeException('invalid filter type');
151+
}
152+
$rows = $this->connection->query('SELECT ptype, v0, v1, v2, v3, v4, v5 FROM '.$this->casbinRuleTableName.'');
153+
foreach($rows as $row) {
154+
if (self::filterLine(array_values($row), $filter)) {
155+
continue;
156+
}
157+
$line = implode(', ', $row);
158+
//var_dump($line);continue;
159+
$this->loadPolicyLine($line, $model);
160+
}
161+
$this->filtered = true;
162+
}
163+
164+
/**
165+
* FilterLine function.
166+
*
167+
* @param array $row
168+
* @param Filter $filter
169+
*
170+
* @return bool
171+
*/
172+
protected static function filterLine(array $row, Filter $filter): bool
173+
{
174+
if (0 == \count($row)) {
175+
return true;
176+
}
177+
178+
$filterSlice = [];
179+
switch (trim($row[0])) {
180+
case 'p':
181+
$filterSlice = $filter->p;
182+
// var_dump($filterSlice);exit;
183+
break;
184+
case 'g':
185+
$filterSlice = $filter->g;
186+
187+
break;
188+
}
189+
190+
return self::filterWords($row, $filterSlice);
191+
}
192+
193+
/**
194+
* FilterWords function.
195+
*
196+
* @param array $line ['p', 'alice', 'data1', 'read']
197+
* @param array $filter ['alice']
198+
*
199+
* @return bool
200+
*/
201+
protected static function filterWords(array $line, array $filter): bool
202+
{
203+
if (count($line) < count($filter) + 1) {
204+
return true;
205+
}
206+
$skipLine = false;
207+
// var_dump($filter);exit;
208+
// $i从0开始,依次递增
209+
// $filter中的第n个元素和$line中的第n+1个元素比较,不想等就跳过这一行(继续下一次循环,不会执行循环体下面的代码)
210+
foreach ($filter as $i => $v) {
211+
//var_dump($filter, $i, $v, $line[$i + 1]);exit;
212+
if (strlen($v) > 0 && \trim($v) != trim($line[$i + 1])) {
213+
$skipLine = true;
214+
215+
break;
216+
}
217+
}
218+
// var_dump($line, $filter, $skipLine);
219+
return $skipLine;
220+
}
221+
222+
}

0 commit comments

Comments
 (0)