sergmoro1 / laravel-rbac
基于Yii3包的Laravel角色基于访问控制(RBAC)
v1.0.0
2024-05-17 14:47 UTC
Requires
- php: ^8.1|^8.2
- illuminate/support: ^10.0|^11.0
- yiisoft/rbac: ^2.0
- yiisoft/rbac-php: ^2.0
- yiisoft/rbac-rules-container: ^2.1
Requires (Dev)
- orchestra/testbench: ^6.0
README
此包将Yii 基于角色的访问控制和PHP 存储适配到Laravel。
安装
composer require sergmoro1/laravel-rbac
发布RBAC示例
php artisan vendor:publish --tag=rbac-sample
在发布示例之后,可以将类 App\Concole\Commands\Rbac
用作您自己的访问系统的基准。
绑定 AccessCheckerInterface
和其实现
修改文件 App\Providers\AppServiceProvider
。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Yiisoft\Access\AccessCheckerInterface;
use Yiisoft\Rbac\Manager;
use Yiisoft\Rbac\SimpleRuleFactory;
use Yiisoft\Rbac\Php\AssignmentsStorage;
use Yiisoft\Rbac\Php\ItemsStorage;
use Yiisoft\Rbac\Rules\Container\RulesContainer;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->bind(AccessCheckerInterface::class, function ($app) {
$directory = __DIR__ . '/../../storage/rbac';
$itemsStorage = new ItemsStorage($directory . '/items.php');
$assignmentsStorage = new AssignmentsStorage($directory . '/assignments.php');
$rulesContainer = new RulesContainer(app());
return new Manager($itemsStorage, $assignmentsStorage, $rulesContainer);
});
}
}
RBAC初始化
在执行以下命令之前,请编辑类 App\Console\Commands\Rbac
中用户的角色分配。
php artisan rbac:init
示例
示例假定您已经定义了一个 Post
模型。作者可以添加帖子并仅编辑自己的帖子。管理员也可以添加帖子,但可以编辑所有帖子。对以下类进行一些修改。
User
模型
const ROLE_ADMIN = 'admin';
const ROLE_AUTHOR = 'author';
控制器
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Yiisoft\Access\AccessCheckerInterface;
class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
public function __construct(private AccessCheckerInterface $accessChecker)
{
}
/**
* Checking the permission to perform the action.
*
* @param string $action
* @param array $params
*/
protected function checkAccess(string $action, $params = [])
{
$userId = auth()->id();
if (!$this->accessChecker->userHasPermission($userId, $action, $params)) {
abort(403, 'Access denied');
}
}
}
PostController
<?php
namespace App\Http\Controllers;
class PostController extends Controller
{
public function create()
{
$this->checkAccess('createPost');
$post = new Post();
$post->status = Post::STATUS_DRAFT;
return view('post', ['post' => $post, 'action' => 'create']);
}
public function edit(int $id)
{
$post = Post::find($id);
$this->checkAccess('updatePost', ['user_id' => $post->user_id]);
return view('post', ['post' => $post, 'action' => 'edit']);
}
规则
请注意在Rbac命令中使用的复合规则。
$manager->addPermission((new Permission('updatePost'))->withRuleName(AdminOrOwnerRule::class));
这样,可以设置复杂的行为权限验证规则。
<?php
namespace App\Console\Commands\Rbac\Rules;
class AdminOrOwnerRule implements RuleInterface
{
private $compositeRule;
public function __construct()
{
$this->compositeRule = new CompositeRule(CompositeRule::OR, [AdminRule::class, OwnerRule::class]);
}
public function execute(?string $userId, Item $item, RuleContext $context): bool
{
return $this->compositeRule->execute($userId, $item, $context);
}
}