Support for multiple enforcers.

This commit is contained in:
root 2019-09-04 11:57:38 +08:00
parent 4e53d87672
commit 6e69d2b8dd
6 changed files with 350 additions and 249 deletions

0
README.md Normal file → Executable file
View File

0
composer.json Normal file → Executable file
View File

340
src/Adapters/DatabaseAdapter.php Normal file → Executable file
View File

@ -1,171 +1,169 @@
<?php <?php
namespace Lauthz\Adapters; namespace Lauthz\Adapters;
use Lauthz\Models\Rule; use Lauthz\Models\Rule;
use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract; use Lauthz\Contracts\DatabaseAdapter as DatabaseAdapterContract;
use Casbin\Persist\AdapterHelper; use Casbin\Persist\AdapterHelper;
/** /**
* DatabaseAdapter. * DatabaseAdapter.
* *
* @author techlee@qq.com * @author techlee@qq.com
*/ */
class DatabaseAdapter implements DatabaseAdapterContract class DatabaseAdapter implements DatabaseAdapterContract
{ {
use AdapterHelper; use AdapterHelper;
/** /**
* Rules eloquent model. * Rules eloquent model.
* *
* @var Rule * @var Rule
*/ */
protected $eloquent; protected $eloquent;
/** /**
* the DatabaseAdapter constructor. * the DatabaseAdapter constructor.
* *
* @param Rule $eloquent * @param Rule $eloquent
*/ */
public function __construct(Rule $eloquent) public function __construct(Rule $eloquent)
{ {
$this->eloquent = $eloquent; $this->eloquent = $eloquent;
} }
/** /**
* savePolicyLine function. * savePolicyLine function.
* *
* @param string $ptype * @param string $ptype
* @param array $rule * @param array $rule
* */
* @return void public function savePolicyLine($ptype, array $rule)
*/ {
public function savePolicyLine($ptype, array $rule) $col['ptype'] = $ptype;
{ foreach ($rule as $key => $value) {
$col['ptype'] = $ptype; $col['v'.strval($key)] = $value;
foreach ($rule as $key => $value) { }
$col['v'.strval($key)] = $value;
} $this->eloquent->create($col);
}
$this->eloquent->create($col);
} /**
* loads all policy rules from the storage.
/** *
* loads all policy rules from the storage. * @param Model $model
* *
* @param Model $model * @return mixed
* */
* @return mixed public function loadPolicy($model)
*/ {
public function loadPolicy($model) $rows = $this->eloquent->getAllFromCache();
{
$rows = $this->eloquent->getAllFromCache(); foreach ($rows as $row) {
$line = implode(', ', array_filter($row, function ($val) {
foreach ($rows as $row) { return '' != $val && !is_null($val);
$line = implode(', ', array_filter($row, function ($val) { }));
return '' != $val && !is_null($val); $this->loadPolicyLine(trim($line), $model);
})); }
$this->loadPolicyLine(trim($line), $model); }
}
} /**
* saves all policy rules to the storage.
/** *
* saves all policy rules to the storage. * @param Model $model
* *
* @param Model $model * @return bool
* */
* @return bool public function savePolicy($model)
*/ {
public function savePolicy($model) foreach ($model->model['p'] as $ptype => $ast) {
{ foreach ($ast->policy as $rule) {
foreach ($model->model['p'] as $ptype => $ast) { $this->savePolicyLine($ptype, $rule);
foreach ($ast->policy as $rule) { }
$this->savePolicyLine($ptype, $rule); }
}
} foreach ($model->model['g'] as $ptype => $ast) {
foreach ($ast->policy as $rule) {
foreach ($model->model['g'] as $ptype => $ast) { $this->savePolicyLine($ptype, $rule);
foreach ($ast->policy as $rule) { }
$this->savePolicyLine($ptype, $rule); }
}
} return true;
}
return true;
} /**
* Adds a policy rule to the storage.
/** * This is part of the Auto-Save feature.
* Adds a policy rule to the storage. *
* This is part of the Auto-Save feature. * @param string $sec
* * @param string $ptype
* @param string $sec * @param array $rule
* @param string $ptype *
* @param array $rule * @return mixed
* */
* @return mixed public function addPolicy($sec, $ptype, $rule)
*/ {
public function addPolicy($sec, $ptype, $rule) return $this->savePolicyLine($ptype, $rule);
{ }
return $this->savePolicyLine($ptype, $rule);
} /**
* This is part of the Auto-Save feature.
/** *
* This is part of the Auto-Save feature. * @param string $sec
* * @param string $ptype
* @param string $sec * @param array $rule
* @param string $ptype *
* @param array $rule * @return mixed
* */
* @return mixed public function removePolicy($sec, $ptype, $rule)
*/ {
public function removePolicy($sec, $ptype, $rule) $count = 0;
{
$count = 0; $instance = $this->eloquent->where('ptype', $ptype);
$instance = $this->eloquent->where('ptype', $ptype); foreach ($rule as $key => $value) {
$instance->where('v'.strval($key), $value);
foreach ($rule as $key => $value) { }
$instance->where('v'.strval($key), $value);
} foreach ($instance->get() as $model) {
if ($model->delete()) {
foreach ($instance->get() as $model) { ++$count;
if ($model->delete()) { }
++$count; }
}
} return $count;
}
return $count;
} /**
* RemoveFilteredPolicy removes policy rules that match the filter from the storage.
/** * This is part of the Auto-Save feature.
* RemoveFilteredPolicy removes policy rules that match the filter from the storage. *
* This is part of the Auto-Save feature. * @param string $sec
* * @param string $ptype
* @param string $sec * @param int $fieldIndex
* @param string $ptype * @param mixed ...$fieldValues
* @param int $fieldIndex *
* @param mixed ...$fieldValues * @return mixed
* */
* @return mixed public function removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues)
*/ {
public function removeFilteredPolicy($sec, $ptype, $fieldIndex, ...$fieldValues) $count = 0;
{
$count = 0; $instance = $this->eloquent->where('ptype', $ptype);
foreach (range(0, 5) as $value) {
$instance = $this->eloquent->where('ptype', $ptype); if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) {
foreach (range(0, 5) as $value) { if ('' != $fieldValues[$value - $fieldIndex]) {
if ($fieldIndex <= $value && $value < $fieldIndex + count($fieldValues)) { $instance->where('v'.strval($value), $fieldValues[$value - $fieldIndex]);
if ('' != $fieldValues[$value - $fieldIndex]) { }
$instance->where('v'.strval($value), $fieldValues[$value - $fieldIndex]); }
} }
}
} foreach ($instance->get() as $model) {
if ($model->delete()) {
foreach ($instance->get() as $model) { ++$count;
if ($model->delete()) { }
++$count; }
}
} return $count;
}
return $count; }
}
}

110
src/EnforcerManager.php Normal file → Executable file
View File

@ -6,34 +6,75 @@ use Casbin\Enforcer;
use Casbin\Model\Model; use Casbin\Model\Model;
use Casbin\Log\Log; use Casbin\Log\Log;
use Lauthz\Contracts\Factory; use Lauthz\Contracts\Factory;
use Illuminate\Support\Manager; use Lauthz\Models\Rule;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use InvalidArgumentException;
/** /**
* @mixin \Casbin\Enforcer * @mixin \Casbin\Enforcer
*/ */
class EnforcerManager extends Manager implements Factory class EnforcerManager implements Factory
{ {
/** /**
* Get the default driver name. * The application instance.
* *
* @return string * @var \Illuminate\Foundation\Application
*/ */
public function getDefaultDriver() protected $app;
/**
* The array of created "guards".
*
* @var array
*/
protected $guards = [];
/**
* Create a new manager instance.
*
* @param \Illuminate\Foundation\Application $app
*/
public function __construct($app)
{ {
return $this->app['config']['lauthz.default']; $this->app = $app;
} }
/** /**
* Create an instance of the Basic Enforcer driver. * Attempt to get the enforcer from the local cache.
* *
* @param array $config * @param string $name
* *
* @return \Casbin\Enforcer * @return \Casbin\Enforcer
*
* @throws \InvalidArgumentException
*/ */
public function createBasicDriver() public function guard($name = null)
{ {
$config = $this->getConfig('basic'); $name = $name ?: $this->getDefaultGuard();
if (!isset($this->guards[$name])) {
$this->guards[$name] = $this->resolve($name);
}
return $this->guards[$name];
}
/**
* Resolve the given guard.
*
* @param string $name
*
* @return \Casbin\Enforcer
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Enforcer [{$name}] is not defined.");
}
if ($logger = Arr::get($config, 'log.logger')) { if ($logger = Arr::get($config, 'log.logger')) {
Log::setLogger(new $logger($this->app['log'])); Log::setLogger(new $logger($this->app['log']));
@ -48,7 +89,9 @@ class EnforcerManager extends Manager implements Factory
} }
$adapter = Arr::get($config, 'adapter'); $adapter = Arr::get($config, 'adapter');
if (!is_null($adapter)) { if (!is_null($adapter)) {
$adapter = $this->app->make($adapter); $adapter = $this->app->make($adapter, [
'eloquent' => new Rule([], $name),
]);
} }
return new Enforcer($model, $adapter, Arr::get($config, 'log.enabled', false)); return new Enforcer($model, $adapter, Arr::get($config, 'log.enabled', false));
@ -65,4 +108,49 @@ class EnforcerManager extends Manager implements Factory
{ {
return $this->app['config']["lauthz.{$name}"]; return $this->app['config']["lauthz.{$name}"];
} }
/**
* Get the default enforcer guard name.
*
* @return string
*/
public function getDefaultGuard()
{
return $this->app['config']['lauthz.default'];
}
/**
* Set the default guard driver the factory should serve.
*
* @param string $name
*/
public function shouldUse($name)
{
$name = $name ?: $this->getDefaultGuard();
$this->setDefaultGuard($name);
}
/**
* Set the default authorization guard name.
*
* @param string $name
*/
public function setDefaultGuard($name)
{
$this->app['config']['lauthz.default'] = $name;
}
/**
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
*
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
} }

127
src/Middlewares/RequestMiddleware.php Normal file → Executable file
View File

@ -1,61 +1,66 @@
<?php <?php
namespace Lauthz\Middlewares; namespace Lauthz\Middlewares;
use Closure; use Closure;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Lauthz\Exceptions\UnauthorizedException; use Illuminate\Http\Request;
use Lauthz\Facades\Enforcer; use Lauthz\Exceptions\UnauthorizedException;
use Lauthz\Facades\Enforcer;
/**
* A HTTP Request Middleware. /**
*/ * A HTTP Request Middleware.
class RequestMiddleware */
{ class RequestMiddleware
/** {
* The authentication factory instance. /**
* * Handle an incoming request.
* @var \Illuminate\Contracts\Auth\Factory *
*/ * @param \Illuminate\Http\Request $request
protected $auth; * @param \Closure $next
* @param mixed ...$guards
/** *
* Create a new middleware instance. * @return mixed
* */
* @param \Illuminate\Contracts\Auth\Factory $auth public function handle($request, Closure $next, ...$guards)
* {
* @return void if (Auth::guest()) {
*/ throw new UnauthorizedException();
public function __construct(Auth $auth) }
{
$this->auth = $auth; $this->authorize($request, $guards);
}
return $next($request);
/** }
* Handle an incoming request.
* /**
* @param \Illuminate\Http\Request $request * Determine if the user is authorized in to any of the given guards.
* @param \Closure $next *
* @param mixed ...$args * @param \Illuminate\Http\Request $request
* * @param array $guards
* @return mixed *
*/ * @throws \Lauthz\Exceptions\UnauthorizedException
public function handle($request, Closure $next) */
{ protected function authorize(Request $request, array $guards)
if (Auth::guest()) { {
throw new UnauthorizedException(); $user = Auth::user();
} $identifier = $user->getAuthIdentifier();
if (method_exists($user, 'getAuthzIdentifier')) {
$user = Auth::user(); $identifier = $user->getAuthzIdentifier();
$identifier = $user->getAuthIdentifier(); }
if (method_exists($user, 'getAuthzIdentifier')) {
$identifier = $user->getAuthzIdentifier(); if (empty($guards)) {
} if (Enforcer::enforce($identifier, $request->getPathInfo(), $request->method())) {
return;
if (!Enforcer::enforce($identifier, $request->getPathInfo(), $request->method())) { }
throw new UnauthorizedException(); }
}
foreach ($guards as $guard) {
return $next($request); if (Enforcer::guard($guard)->enforce($identifier, $request->getPathInfo(), $request->method())) {
} return Enforcer::shouldUse($guard);
} }
}
throw new UnauthorizedException();
}
}

22
src/Models/Rule.php Normal file → Executable file
View File

@ -17,6 +17,13 @@ class Rule extends Model
*/ */
protected $store; protected $store;
/**
* the guard for lauthz.
*
* @var string
*/
protected $guard;
/** /**
* Fillable. * Fillable.
* *
@ -27,10 +34,16 @@ class Rule extends Model
/** /**
* Create a new Eloquent model instance. * Create a new Eloquent model instance.
* *
* @param array $attributes * @param array $attributes
* @param string $guard
*/ */
public function __construct(array $attributes = []) public function __construct(array $attributes = [], $guard = '')
{ {
$this->guard = $guard;
if (!$guard) {
$this->guard = config('lauthz.default');
}
$connection = $this->config('database.connection') ?: config('database.default'); $connection = $this->config('database.connection') ?: config('database.default');
$this->setConnection($connection); $this->setConnection($connection);
@ -84,7 +97,6 @@ class Rule extends Model
*/ */
protected function initCache() protected function initCache()
{ {
$driver = config('lauthz.default');
$store = $this->config('cache.store', 'default'); $store = $this->config('cache.store', 'default');
$store = 'default' == $store ? null : $store; $store = 'default' == $store ? null : $store;
$this->store = Cache::store($store); $this->store = Cache::store($store);
@ -100,8 +112,6 @@ class Rule extends Model
*/ */
protected function config($key = null, $default = null) protected function config($key = null, $default = null)
{ {
$driver = config('lauthz.default'); return config('lauthz.'.$this->guard.'.'.$key, $default);
return config('lauthz.'.$driver.'.'.$key, $default);
} }
} }