sergmoro1/laravel-rbac

基于Yii3包的Laravel角色基于访问控制(RBAC)

v1.0.0 2024-05-17 14:47 UTC

This package is auto-updated.

Last update: 2024-09-17 16:15:32 UTC


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);
    }
}