feat: support Casbin FilteredAdapter interface

fix: add  property

fix: include necessary class

fix: add support for invalid filter type

fix: use try catch to invalid filter type
This commit is contained in:
basakest 2021-03-24 22:51:14 +08:00
parent bb566321bb
commit eebf5bd5eb
3 changed files with 121 additions and 3 deletions

View File

@ -8,18 +8,26 @@ use Lauthz\Models\Rule;
use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract;
use Lauthz\Contracts\BatchDatabaseAdapter as BatchDatabaseAdapterContract;
use Lauthz\Contracts\UpdatableDatabaseAdapter as UpdatableDatabaseAdapterContract;
use Lauthz\Contracts\FilteredDatabaseAdapter as FilteredDatabaseAdapterContract;
use Casbin\Persist\Adapters\Filter;
use Casbin\Model\Model;
use Casbin\Persist\AdapterHelper;
use DateTime;
use Casbin\Exceptions\InvalidFilterTypeException;
/**
* DatabaseAdapter.
*
* @author techlee@qq.com
*/
class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract
class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterContract, UpdatableDatabaseAdapterContract, FilteredDatabaseAdapterContract
{
use AdapterHelper;
/**
* @var bool
*/
private $filtered = false;
/**
* Rules eloquent model.
*
@ -232,4 +240,59 @@ class DatabaseAdapter implements DatabaseAdapterContract, BatchDatabaseAdapterCo
}
$instance->update($update);
}
/**
* Loads only policy rules that match the filter.
*
* @param Model $model
* @param mixed $filter
*/
public function loadFilteredPolicy(Model $model, $filter): void
{
$instance = $this->eloquent;
if (is_string($filter)) {
$filter = str_replace(' ', '', $filter);
$filter = explode('=', $filter);
$instance = $instance->where($filter[0], $filter[1]);
} else if ($filter instanceof Filter) {
foreach($filter->p as $k => $v) {
$where[$v] = $filter->g[$k];
$instance = $instance->where($v, $filter->g[$k]);
}
} else if ($filter instanceof \Closure) {
$filter($instance);
} else {
throw new InvalidFilterTypeException('invalid filter type');
}
$rows = $instance->get()->makeHidden(['created_at','updated_at', 'id'])->toArray();
foreach ($rows as $row) {
$row = array_filter($row, function($value) { return !is_null($value) && $value !== ''; });
$line = implode(', ', array_filter($row, function ($val) {
return '' != $val && !is_null($val);
}));
$this->loadPolicyLine(trim($line), $model);
}
$this->setFiltered(true);
}
/**
* Returns true if the loaded policy has been filtered.
*
* @return bool
*/
public function isFiltered(): bool
{
return $this->filtered;
}
/**
* Sets filtered parameter.
*
* @param bool $filtered
*/
public function setFiltered(bool $filtered): void
{
$this->filtered = $filtered;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Lauthz\Contracts;
use Casbin\Persist\FilteredAdapter;
interface FilteredDatabaseAdapter extends FilteredAdapter
{
}

View File

@ -4,7 +4,9 @@ namespace Lauthz\Tests;
use Enforcer;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Casbin\Persist\Adapters\Filter;
use Lauthz\Models\Rule;
use Casbin\Exceptions\InvalidFilterTypeException;
class DatabaseAdapterTest extends TestCase
{
use DatabaseMigrations;
@ -128,4 +130,48 @@ class DatabaseAdapterTest extends TestCase
['data2_admin', 'data2', 'write'],
], Enforcer::getPolicy());
}
public function testLoadFilteredPolicy()
{
$this->initTable();
Enforcer::clearPolicy();
$this->initConfig();
$adapter = Enforcer::getAdapter();
$adapter->setFiltered(true);
$this->assertEquals([], Enforcer::getPolicy());
// invalid filter type
try {
$filter = ['alice', 'data1', 'read'];
Enforcer::loadFilteredPolicy($filter);
$e = InvalidFilterTypeException::class;
$this->fail("Expected exception $e not thrown");
} catch (InvalidFilterTypeException $e) {
$this->assertEquals("invalid filter type", $e->getMessage());
}
// string
$filter = "v0 = bob";
Enforcer::loadFilteredPolicy($filter);
$this->assertEquals([
['bob', 'data2', 'write']
], Enforcer::getPolicy());
// Filter
$filter = new Filter(['v2'], ['read']);
Enforcer::loadFilteredPolicy($filter);
$this->assertEquals([
['alice', 'data1', 'read'],
['data2_admin', 'data2', 'read'],
], Enforcer::getPolicy());
// Closure
Enforcer::loadFilteredPolicy(function (Rule &$rule) {
$rule = $rule->where('v1', 'data1');
});
$this->assertEquals([
['alice', 'data1', 'read'],
], Enforcer::getPolicy());
}
}