Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
a050a9c222 | |
![]() |
434ee8003f | |
![]() |
11ffe28750 |
|
@ -27,73 +27,7 @@ jobs:
|
||||||
# laravel: [ ]
|
# laravel: [ ]
|
||||||
# stability: [ prefer-lowest, prefer-stable ]
|
# stability: [ prefer-lowest, prefer-stable ]
|
||||||
include:
|
include:
|
||||||
# Laravel 5.5
|
|
||||||
- php: 7.1
|
|
||||||
laravel: 5.5.*
|
|
||||||
phpunit: ~6.0
|
|
||||||
- php: 7.2
|
|
||||||
laravel: 5.5.*
|
|
||||||
phpunit: ~6.0
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 5.5.*
|
|
||||||
phpunit: ~6.0
|
|
||||||
|
|
||||||
# Laravel 5.6
|
|
||||||
- php: 7.1
|
|
||||||
laravel: 5.6.*
|
|
||||||
phpunit: ~7.0
|
|
||||||
- php: 7.2
|
|
||||||
laravel: 5.6.*
|
|
||||||
phpunit: ~7.0
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 5.6.*
|
|
||||||
phpunit: ~7.0
|
|
||||||
|
|
||||||
# Laravel 5.7
|
|
||||||
- php: 7.1
|
|
||||||
laravel: 5.7.*
|
|
||||||
phpunit: ~7.5
|
|
||||||
- php: 7.2
|
|
||||||
laravel: 5.7.*
|
|
||||||
phpunit: ~7.5
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 5.7.*
|
|
||||||
phpunit: ~7.5
|
|
||||||
|
|
||||||
# Laravel 5.8
|
|
||||||
- php: 7.1
|
|
||||||
laravel: 5.8.*
|
|
||||||
phpunit: ~7.5
|
|
||||||
- php: 7.2
|
|
||||||
laravel: 5.8.*
|
|
||||||
phpunit: ~8.0
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 5.8.*
|
|
||||||
phpunit: ~8.0
|
|
||||||
|
|
||||||
# Laravel 6.x
|
|
||||||
- php: 7.2
|
|
||||||
laravel: 6.*
|
|
||||||
phpunit: ~8.0
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 6.*
|
|
||||||
phpunit: ~8.0
|
|
||||||
|
|
||||||
# Laravel 7.x
|
|
||||||
- php: 7.3
|
|
||||||
laravel: 7.*
|
|
||||||
phpunit: ~9.0
|
|
||||||
- php: 7.4
|
|
||||||
laravel: 7.*
|
|
||||||
phpunit: ~9.0
|
|
||||||
|
|
||||||
# Laravel 8.x
|
# Laravel 8.x
|
||||||
- php: 7.3
|
|
||||||
laravel: 8.*
|
|
||||||
phpunit: ~9.0
|
|
||||||
- php: 7.4
|
|
||||||
laravel: 8.*
|
|
||||||
phpunit: ~9.0
|
|
||||||
- php: 8.0
|
- php: 8.0
|
||||||
laravel: 8.*
|
laravel: 8.*
|
||||||
phpunit: ~9.0
|
phpunit: ~9.0
|
||||||
|
|
16
README.md
16
README.md
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/php-casbin/laravel-authz/actions">
|
<a href="https://github.com/php-casbin/laravel-authz/actions">
|
||||||
<img src="https://github.com/php-casbin/laravel-authz/workflows/build/badge.svg?branch=master" alt="Build Status">
|
<img src="https://github.com/php-casbin/laravel-authz/actions/workflows/build.yml/badge.svg?branch=master" alt="Build Status">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://coveralls.io/github/php-casbin/laravel-authz">
|
<a href="https://coveralls.io/github/php-casbin/laravel-authz">
|
||||||
<img src="https://coveralls.io/repos/github/php-casbin/laravel-authz/badge.svg" alt="Coverage Status">
|
<img src="https://coveralls.io/repos/github/php-casbin/laravel-authz/badge.svg" alt="Coverage Status">
|
||||||
|
@ -35,6 +35,7 @@ All you need to learn to use `Casbin` first.
|
||||||
* [Using a middleware](#using-a-middleware)
|
* [Using a middleware](#using-a-middleware)
|
||||||
* [basic Enforcer Middleware](#basic-enforcer-middleware)
|
* [basic Enforcer Middleware](#basic-enforcer-middleware)
|
||||||
* [HTTP Request Middleware ( RESTful is also supported )](#http-request-middleware--restful-is-also-supported-)
|
* [HTTP Request Middleware ( RESTful is also supported )](#http-request-middleware--restful-is-also-supported-)
|
||||||
|
* [Using Gates](#using-gates)
|
||||||
* [Multiple enforcers](#multiple-enforcers)
|
* [Multiple enforcers](#multiple-enforcers)
|
||||||
* [Using artisan commands](#using-artisan-commands)
|
* [Using artisan commands](#using-artisan-commands)
|
||||||
* [Cache](#using-cache)
|
* [Cache](#using-cache)
|
||||||
|
@ -277,6 +278,19 @@ Route::group(['middleware' => ['http_request']], function () {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Using Gates
|
||||||
|
|
||||||
|
You can use Laravel Gates to check if a user has a permission, provided that you have set an existing user instance as the currently authenticated user.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$user->can('articles,read');
|
||||||
|
// For multiple enforcers
|
||||||
|
$user->can('articles,read', 'second');
|
||||||
|
// The methods cant, cannot, canAny, etc. also work
|
||||||
|
```
|
||||||
|
|
||||||
|
If you require custom Laravel Gates, you can disable the automatic registration by setting `enabled_register_at_gates` to `false` in the lauthz file. After that, you can use `Gates::before` or `Gates::after` in your ServiceProvider to register custom Gates. See [Gates](https://laravel.com/docs/11.x/authorization#gates) for more details.
|
||||||
|
|
||||||
### Multiple enforcers
|
### Multiple enforcers
|
||||||
|
|
||||||
If you need multiple permission controls in your project, you can configure multiple enforcers.
|
If you need multiple permission controls in your project, you can configure multiple enforcers.
|
||||||
|
|
|
@ -20,18 +20,17 @@
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.1.0",
|
"php": ">=8.0",
|
||||||
"illuminate/support": "~5.5|~6.0|~7.0|~8.0|~9.0|~10.0|~11.0",
|
"illuminate/support": "~8.0|~9.0|~10.0|~11.0",
|
||||||
"illuminate/database": "~5.5|~6.0|~7.0|~8.0|~9.0|~10.0|~11.0",
|
"illuminate/database": "~8.0|~9.0|~10.0|~11.0",
|
||||||
"illuminate/console": "~5.5|~6.0|~7.0|~8.0|~9.0|~10.0|~11.0",
|
"illuminate/console": "~8.0|~9.0|~10.0|~11.0",
|
||||||
"casbin/casbin": "~3.1",
|
"casbin/casbin": "~4.0"
|
||||||
"casbin/psr3-bridge": "^1.1"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~7.0|~8.0|~9.0|~10.5",
|
"phpunit/phpunit": "~9.0|~10.5",
|
||||||
"php-coveralls/php-coveralls": "^2.4",
|
"php-coveralls/php-coveralls": "^2.7",
|
||||||
"mockery/mockery": "^1.0",
|
"mockery/mockery": "^1.0",
|
||||||
"laravel/laravel": "~5.5|~6.0|~7.0|~8.0|~9.0|~10.0|~11.0"
|
"laravel/laravel": "~9.0|~10.0|~11.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|
|
@ -6,6 +6,14 @@ return [
|
||||||
*/
|
*/
|
||||||
'default' => 'basic',
|
'default' => 'basic',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lauthz Localizer
|
||||||
|
*/
|
||||||
|
'localizer' => [
|
||||||
|
// changes whether enforcer will register at gates.
|
||||||
|
'enabled_register_at_gates' => true
|
||||||
|
],
|
||||||
|
|
||||||
'basic' => [
|
'basic' => [
|
||||||
/*
|
/*
|
||||||
* Casbin model setting.
|
* Casbin model setting.
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lauthz;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\Access\Authorizable;
|
||||||
|
use Illuminate\Contracts\Auth\Access\Gate;
|
||||||
|
use Lauthz\Facades\Enforcer;
|
||||||
|
|
||||||
|
class EnforcerLocalizer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The application instance.
|
||||||
|
*
|
||||||
|
* @var \Illuminate\Foundation\Application
|
||||||
|
*/
|
||||||
|
protected $app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new localizer instance.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Foundation\Application $app
|
||||||
|
*/
|
||||||
|
public function __construct($app)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the localizer based on the configuration.
|
||||||
|
*/
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
if ($this->app->config->get('lauthz.localizer.enabled_register_at_gates')) {
|
||||||
|
$this->registerAtGate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the localizer at the gate.
|
||||||
|
*/
|
||||||
|
protected function registerAtGate()
|
||||||
|
{
|
||||||
|
$this->app->make(Gate::class)->before(function (Authorizable $user, string $ability, array $guards) {
|
||||||
|
/** @var \Illuminate\Contracts\Auth\Authenticatable $user */
|
||||||
|
$identifier = $user->getAuthIdentifier();
|
||||||
|
if (method_exists($user, 'getAuthzIdentifier')) {
|
||||||
|
/** @var \Lauthz\Tests\Models\User $user */
|
||||||
|
$identifier = $user->getAuthzIdentifier();
|
||||||
|
}
|
||||||
|
$identifier = strval($identifier);
|
||||||
|
$ability = explode(',', $ability);
|
||||||
|
if (empty($guards)) {
|
||||||
|
return Enforcer::enforce($identifier, ...$ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($guards as $guard) {
|
||||||
|
return Enforcer::guard($guard)->enforce($identifier, ...$ability);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace Lauthz;
|
namespace Lauthz;
|
||||||
|
|
||||||
use Casbin\Bridge\Logger\LoggerBridge;
|
|
||||||
use Casbin\Enforcer;
|
use Casbin\Enforcer;
|
||||||
use Casbin\Model\Model;
|
use Casbin\Model\Model;
|
||||||
use Casbin\Log\Log;
|
use Casbin\Log\Log;
|
||||||
|
use Casbin\Log\Logger\DefaultLogger;
|
||||||
use Lauthz\Contracts\Factory;
|
use Lauthz\Contracts\Factory;
|
||||||
use Lauthz\Models\Rule;
|
use Lauthz\Models\Rule;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
@ -80,10 +80,10 @@ class EnforcerManager implements Factory
|
||||||
|
|
||||||
if ($logger = Arr::get($config, 'log.logger')) {
|
if ($logger = Arr::get($config, 'log.logger')) {
|
||||||
if (is_string($logger)) {
|
if (is_string($logger)) {
|
||||||
$logger = $this->app->make($logger);
|
$logger = new DefaultLogger($this->app->make($logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::setLogger(new LoggerBridge($logger));
|
Log::setLogger($logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
$model = new Model();
|
$model = new Model();
|
||||||
|
@ -98,7 +98,7 @@ class EnforcerManager implements Factory
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Enforcer($model, $adapter, Arr::get($config, 'log.enabled', false));
|
return new Enforcer($model, $adapter, $logger, Arr::get($config, 'log.enabled', false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Lauthz;
|
namespace Lauthz;
|
||||||
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Lauthz\EnforcerLocalizer;
|
||||||
use Lauthz\Loaders\ModelLoaderManager;
|
use Lauthz\Loaders\ModelLoaderManager;
|
||||||
use Lauthz\Models\Rule;
|
use Lauthz\Models\Rule;
|
||||||
use Lauthz\Observers\RuleObserver;
|
use Lauthz\Observers\RuleObserver;
|
||||||
|
@ -31,6 +32,8 @@ class LauthzServiceProvider extends ServiceProvider
|
||||||
$this->mergeConfigFrom(__DIR__ . '/../config/lauthz.php', 'lauthz');
|
$this->mergeConfigFrom(__DIR__ . '/../config/lauthz.php', 'lauthz');
|
||||||
|
|
||||||
$this->bootObserver();
|
$this->bootObserver();
|
||||||
|
|
||||||
|
$this->registerLocalizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,5 +58,19 @@ class LauthzServiceProvider extends ServiceProvider
|
||||||
$this->app->singleton(ModelLoaderManager::class, function ($app) {
|
$this->app->singleton(ModelLoaderManager::class, function ($app) {
|
||||||
return new ModelLoaderManager($app);
|
return new ModelLoaderManager($app);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->app->singleton(EnforcerLocalizer::class, function ($app) {
|
||||||
|
return new EnforcerLocalizer($app);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a gate that allows users to use Laravel's built-in Gate to call Enforcer.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function registerLocalizer()
|
||||||
|
{
|
||||||
|
$this->app->make(EnforcerLocalizer::class)->register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ class EnforcerMiddleware
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$identifier = $user->getAuthIdentifier();
|
$identifier = $user->getAuthIdentifier();
|
||||||
if (method_exists($user, 'getAuthzIdentifier')) {
|
if (method_exists($user, 'getAuthzIdentifier')) {
|
||||||
|
/** @var \Lauthz\Tests\Models\User $user */
|
||||||
$identifier = $user->getAuthzIdentifier();
|
$identifier = $user->getAuthzIdentifier();
|
||||||
}
|
}
|
||||||
$identifier = strval($identifier);
|
$identifier = strval($identifier);
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
|
|
||||||
namespace Lauthz\Tests;
|
namespace Lauthz\Tests;
|
||||||
|
|
||||||
use Enforcer;
|
|
||||||
use Lauthz\Models\Rule;
|
use Lauthz\Models\Rule;
|
||||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
use Casbin\Persist\Adapters\Filter;
|
use Lauthz\Facades\Enforcer;
|
||||||
use Casbin\Exceptions\InvalidFilterTypeException;
|
|
||||||
|
|
||||||
class DatabaseAdapterForCacheTest extends TestCase
|
class DatabaseAdapterForCacheTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace Lauthz\Tests;
|
namespace Lauthz\Tests;
|
||||||
|
|
||||||
use Enforcer;
|
|
||||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
use Casbin\Persist\Adapters\Filter;
|
use Casbin\Persist\Adapters\Filter;
|
||||||
use Casbin\Exceptions\InvalidFilterTypeException;
|
use Casbin\Exceptions\InvalidFilterTypeException;
|
||||||
|
use Lauthz\Facades\Enforcer;
|
||||||
|
|
||||||
class DatabaseAdapterTest extends TestCase
|
class DatabaseAdapterTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\Access\Gate;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Lauthz\Tests\TestCase;
|
||||||
|
|
||||||
|
class EnforcerCustomLocalizerTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseMigrations;
|
||||||
|
|
||||||
|
public function testCustomRegisterAtGatesBefore()
|
||||||
|
{
|
||||||
|
$user = $this->user("alice");
|
||||||
|
$this->assertFalse($user->can('data3,read'));
|
||||||
|
|
||||||
|
app(Gate::class)->before(function () {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertTrue($user->can('data3,read'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCustomRegisterAtGatesDefine()
|
||||||
|
{
|
||||||
|
$user = $this->user("alice");
|
||||||
|
$this->assertFalse($user->can('data3,read'));
|
||||||
|
|
||||||
|
app(Gate::class)->define('data3,read', function () {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->assertTrue($user->can('data3,read'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initConfig()
|
||||||
|
{
|
||||||
|
parent::initConfig();
|
||||||
|
$this->app['config']->set('lauthz.localizer.enabled_register_at_gates', false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\Access\Gate;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Lauthz\Facades\Enforcer;
|
||||||
|
use Lauthz\Tests\TestCase;
|
||||||
|
|
||||||
|
class EnforcerLocalizerTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseMigrations;
|
||||||
|
|
||||||
|
public function testRegisterAtGates()
|
||||||
|
{
|
||||||
|
$user = $this->user('alice');
|
||||||
|
$this->assertTrue($user->can('data1,read'));
|
||||||
|
$this->assertFalse($user->can('data1,write'));
|
||||||
|
$this->assertFalse($user->cannot('data2,read'));
|
||||||
|
|
||||||
|
Enforcer::guard('second')->addPolicy('alice', 'data1', 'read');
|
||||||
|
$this->assertTrue($user->can('data1,read', 'second'));
|
||||||
|
$this->assertFalse($user->can('data3,read', 'second'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNotLogin()
|
||||||
|
{
|
||||||
|
$this->assertFalse(app(Gate::class)->allows('data1,read'));
|
||||||
|
$this->assertTrue(app(Gate::class)->forUser($this->user('alice'))->allows('data1,read'));
|
||||||
|
$this->assertFalse(app(Gate::class)->forUser($this->user('bob'))->allows('data1,read'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAfterLogin()
|
||||||
|
{
|
||||||
|
$this->login('alice');
|
||||||
|
$this->assertTrue(app(Gate::class)->allows('data1,read'));
|
||||||
|
$this->assertTrue(app(Gate::class)->allows('data2,read'));
|
||||||
|
$this->assertTrue(app(Gate::class)->allows('data2,write'));
|
||||||
|
|
||||||
|
$this->login('bob');
|
||||||
|
$this->assertFalse(app(Gate::class)->allows('data1,read'));
|
||||||
|
$this->assertTrue(app(Gate::class)->allows('data2,write'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initConfig()
|
||||||
|
{
|
||||||
|
parent::initConfig();
|
||||||
|
$this->app['config']->set('lauthz.second.model.config_type', 'text');
|
||||||
|
$this->app['config']->set(
|
||||||
|
'lauthz.second.model.config_text',
|
||||||
|
$this->getModelText()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getModelText(): string
|
||||||
|
{
|
||||||
|
return <<<EOT
|
||||||
|
[request_definition]
|
||||||
|
r = sub, obj, act
|
||||||
|
|
||||||
|
[policy_definition]
|
||||||
|
p = sub, obj, act
|
||||||
|
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow))
|
||||||
|
|
||||||
|
[matchers]
|
||||||
|
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
|
||||||
|
EOT;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,9 +27,9 @@ abstract class TestCase extends BaseTestCase
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->app->make(Kernel::class)->bootstrap();
|
$this->app->make(Kernel::class)->bootstrap();
|
||||||
|
$this->initConfig();
|
||||||
|
|
||||||
$this->app->register(\Lauthz\LauthzServiceProvider::class);
|
$this->app->register(\Lauthz\LauthzServiceProvider::class);
|
||||||
$this->initConfig();
|
|
||||||
|
|
||||||
$this->artisan('vendor:publish', ['--provider' => 'Lauthz\LauthzServiceProvider']);
|
$this->artisan('vendor:publish', ['--provider' => 'Lauthz\LauthzServiceProvider']);
|
||||||
$this->artisan('migrate', ['--force' => true]);
|
$this->artisan('migrate', ['--force' => true]);
|
||||||
|
|
Loading…
Reference in New Issue