Skip to content

Foundation/Rbac 使用指南

架构概览

Foundation/Rbac/
├── Contracts/              # 接口定义
│   ├── PermissionChecker.php
│   ├── PermissionResolver.php
│   └── MenuVisibilityChecker.php
├── Resolvers/              # 策略实现(可切换)
│   ├── SnapshotPermissionResolver.php      # V1: 读快照
│   └── RoleBasedPermissionResolver.php     # V2: 读角色
├── Checkers/               # 检查器实现
│   ├── DatabasePermissionChecker.php
│   └── DatabaseMenuVisibilityChecker.php
├── Concerns/               # Trait 混入
│   └── HasLimsPermissions.php
├── Middleware/
│   └── PermissionMiddleware.php
├── Facades/
│   └── LimsRbac.php
├── LimsRbac.php                            # 核心服务
└── LimsRbacServiceProvider.php

1. 在 User Model 中使用 Trait

php
<?php

namespace App\Models;

use App\Foundation\Rbac\Concerns\HasLimsPermissions;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasLimsPermissions;
}

现在 User Model 自动获得权限方法:

php
$user = User::find(1);

// 检查权限
$user->hasPermission('sample.add');
$user->hasAnyPermission(['sample.add', 'sample.edit']);
$user->hasAllPermissions(['sample.add', 'sample.edit']);

// 检查菜单
$user->canViewMenu(123);
$user->getVisibleMenus();

// 检查超管
$user->isSuperAdmin();

// 清除缓存
$user->clearPermissionCache();

2. 使用 Facade(推荐)

php
use App\Foundation\Rbac\Facades\LimsRbac;

// 检查当前用户权限
LimsRbac::check('sample.add');
LimsRbac::check(['sample.add', 'sample.edit']); // OR
LimsRbac::check(['sample.add', 'sample.edit'], true); // AND

// 检查指定用户权限
LimsRbac::userCan($userId, 'sample.add');
LimsRbac::userCan($user, 'sample.add');

// 检查菜单
LimsRbac::canViewMenu(123);
LimsRbac::userCanViewMenu($userId, 123);
LimsRbac::getVisibleMenus();

// 检查超管
LimsRbac::isSuperAdmin();

// 批量检查
$results = LimsRbac::batchCheck(['sample.add', 'sample.edit', 'sample.delete']);
// ['sample.add' => true, 'sample.edit' => false, 'sample.delete' => false]

3. 路由中间件

php
use Illuminate\Support\Facades\Route;

// 单个权限
Route::get('/sample', [SampleController::class, 'index'])
    ->middleware('lims.permission:sample.view');

// 多个权限(OR)- 使用分号分隔
Route::post('/sample', [SampleController::class, 'store'])
    ->middleware('lims.permission:sample.add;sample.edit');

// 多个权限(AND)- 最后加 ;and
Route::delete('/sample/{id}', [SampleController::class, 'destroy'])
    ->middleware('lims.permission:sample.delete;sample.manage;and');

// 路由组
Route::middleware(['auth', 'lims.permission:sample.view'])->group(function () {
    Route::get('/sample', [SampleController::class, 'index']);
    Route::get('/sample/{id}', [SampleController::class, 'show']);
});

重要:多个权限使用**分号(;)**分隔,而非逗号。这是因为 Laravel 中间件会将逗号解析为多个参数。


4. Laravel Gate 集成(自动生效)

php
// 控制器中
public function store(Request $request)
{
    $this->authorize('sample.add');
    
    // 或
    if (Gate::denies('sample.add')) {
        abort(403);
    }
}

// Blade 模板中(Laravel 原生)
@can('sample.add')
    <button>添加样品</button>
@endcan

@cannot('sample.add')
    <p>权限不足</p>
@endcannot

5. 自定义 Blade 指令

blade
{{-- 单个权限 --}}
@permission('sample.add')
    <button>添加样品</button>
@endpermission

{{-- 多个权限(OR) --}}
@anyPermission(['sample.add', 'sample.edit'])
    <button>编辑</button>
@endanyPermission

{{-- 多个权限(AND) --}}
@allPermissions(['sample.add', 'sample.edit'])
    <button>批量操作</button>
@endallPermissions

{{-- 菜单可见性 --}}
@canViewMenu(123)
    <a href="/sample">样品管理</a>
@endcanViewMenu

{{-- 超级管理员 --}}
@superAdmin
    <a href="/admin">管理后台</a>
@endsuperAdmin

6. 配置切换 Resolver

V1:快照模式(当前)

env
# .env
RBAC_RESOLVER=App\Foundation\Rbac\Resolvers\SnapshotPermissionResolver

或配置文件:

php
// config/rbac.php
'resolver' => \App\Foundation\Rbac\Resolvers\SnapshotPermissionResolver::class,

V2:角色模式(切主后)

env
# .env
RBAC_RESOLVER=App\Foundation\Rbac\Resolvers\RoleBasedPermissionResolver

无需修改任何业务代码! 只需切换配置即可。


7. 启用 RBAC 强制模式

env
# .env

# 开发/测试阶段(不拦截)
RBAC_ENFORCE=false

# 生产环境(强制鉴权)
RBAC_ENFORCE=true

# 缓存时间(分钟)
RBAC_CACHE_TTL_MINUTES=10

8. 完整示例

控制器

php
<?php

namespace App\Http\Controllers;

use App\Foundation\Rbac\Facades\LimsRbac;
use Illuminate\Http\Request;

class SampleController extends Controller
{
    public function __construct()
    {
        // 中间件鉴权
        $this->middleware('lims.permission:sample.view')->only(['index', 'show']);
        $this->middleware('lims.permission:sample.add')->only(['create', 'store']);
    }

    public function index()
    {
        // Laravel Gate 鉴权
        $this->authorize('sample.view');

        $samples = Sample::all();
        return view('sample.index', compact('samples'));
    }

    public function store(Request $request)
    {
        // Facade 鉴权
        if (!LimsRbac::check('sample.add')) {
            abort(403);
        }

        // 业务逻辑
        Sample::create($request->validated());

        return redirect()->route('sample.index');
    }

    public function batchDelete(Request $request)
    {
        // 批量检查权限
        $permissions = LimsRbac::batchCheck(['sample.delete', 'sample.manage']);

        if (!$permissions['sample.delete'] || !$permissions['sample.manage']) {
            abort(403, '需要删除和管理权限');
        }

        // 业务逻辑
    }
}

Blade 视图

blade
@extends('layouts.app')

@section('content')
    <div class="container">
        <h1>样品管理</h1>

        {{-- 添加按钮(检查权限) --}}
        @permission('sample.add')
            <a href="{{ route('sample.create') }}" class="btn btn-primary">
                添加样品
            </a>
        @endpermission

        <table class="table">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>名称</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                @foreach($samples as $sample)
                    <tr>
                        <td>{{ $sample->id }}</td>
                        <td>{{ $sample->name }}</td>
                        <td>
                            @anyPermission(['sample.edit', 'sample.view'])
                                <a href="{{ route('sample.show', $sample) }}">查看</a>
                            @endanyPermission

                            @permission('sample.delete')
                                <form method="POST" action="{{ route('sample.destroy', $sample) }}">
                                    @csrf
                                    @method('DELETE')
                                    <button type="submit">删除</button>
                                </form>
                            @endpermission
                        </td>
                    </tr>
                @endforeach
            </tbody>
        </table>
    </div>
@endsection

9. 进阶:自定义 Resolver

如果需要自定义权限解析逻辑,实现 PermissionResolver 接口:

php
<?php

namespace App\CustomResolvers;

use App\Foundation\Rbac\Contracts\PermissionResolver;

class CustomPermissionResolver implements PermissionResolver
{
    public function resolve(int $userId): array
    {
        // 自定义逻辑
        return ['custom_permission' => true];
    }

    public function clearCache(int $userId): void
    {
        // 清除缓存逻辑
    }
}

然后在配置中指定:

php
// config/rbac.php
'resolver' => \App\CustomResolvers\CustomPermissionResolver::class,

10. 性能优化

缓存预热

php
// 预热用户权限缓存
$userIds = [1, 2, 3, 4, 5];

foreach ($userIds as $userId) {
    $resolver = app(\App\Foundation\Rbac\Contracts\PermissionResolver::class);
    $resolver->resolve($userId); // 触发缓存
}

批量清除缓存

php
use Illuminate\Support\Facades\Cache;

// 清除所有用户权限缓存
Cache::flush(); // 谨慎使用

// 或清除特定用户
$user->clearPermissionCache();
LimsRbac::clearUserCache($user);

总结

Foundation/Rbac 架构的核心优势:

  1. 接口分离:依赖接口而非实现,易扩展
  2. 策略可切换:V1 快照 → V2 角色,无缝升级
  3. Laravel 集成:Gate + Blade 原生支持
  4. 便捷 API:Trait + Facade 多种用法
  5. 高性能:缓存 + 批量检查

切换 Resolver 无需改代码,只需改配置!