Skip to content

RBAC 权限系统

CatchAdmin 专业版采用标准的 RBAC(基于角色的访问控制)权限模型,实现用户-角色-权限的多对多关联关系。如需深入了解 RBAC 权限机制,可参考这篇基于角色的访问控制文档。

基本约定

  • 超级管理员不受任何权限控制
  • 对于 RBAC 权限控制,GET 请求默认放行,不受权限限制

权限模块

CatchAdmin 专业版默认不启用权限模块和动态菜单功能。使用前需要先激活权限模块

php
php artisan catch:module:install permissions

TIP

开启之后如果没有权限菜单,可以刷新一下

中间件

权限模块提供专用的权限验证中间件,实现访问控制功能

php
use Catch\Exceptions\FailedException;
use Catch\Facade\Admin;
use Catch\Support\Permission\PermissionExemptionResolver;
use Closure;
use Illuminate\Http\Request;
use Modules\Permissions\Exceptions\PermissionForbidden;
use Modules\User\Models\User;

class PermissionGate
{
    public function handle(Request $request, Closure $next): mixed
    {
        if ($this->isAllowGetRequest($request)) {
            return $next($request);
        }

        if (config('app.env') == 'demo') {
            throw new FailedException('演示环境禁止操作');
        }

        if (app(PermissionExemptionResolver::class)->isExempt($request)) {
            return $next($request);
        }

        /* @var User $user */
        $user = Admin::auth();

        if (! $user->can()) {
            throw new PermissionForbidden;
        }

        return $next($request);
    }

    protected function isAllowGetRequest(Request $request): bool
    {
        return config('catch.request_allowed') && $request->isMethod('get');
    }
}

PermissionExempt 属性

从当前版本开始,权限系统支持通过 PHP Attribute 显式声明某个控制器或某个控制器方法跳过 RBAC 校验。

属性类:

php
namespace Catch\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class PermissionExempt
{
    public function __construct(
        public readonly string|array|null $methods = null
    ) {
    }
}

使用场景

  • 第三方回调接口
  • 内部桥接接口
  • 只需要登录态,不参与角色权限分配的接口

基本用法

作用于方法:

php
use Catch\Attributes\PermissionExempt;

class PayNotifyController
{
    #[PermissionExempt]
    public function callback()
    {
    }
}

按 HTTP Method 生效:

php
use Catch\Attributes\PermissionExempt;

class OpenapiController
{
    #[PermissionExempt('POST')]
    public function notify()
    {
    }

    #[PermissionExempt(['GET', 'POST'])]
    public function sync()
    {
    }
}

作用于整个控制器:

php
use Catch\Attributes\PermissionExempt;

#[PermissionExempt]
class WebhookController
{
    public function store()
    {
    }

    public function update()
    {
    }
}

参数说明

  • null:当前类或方法的全部请求方法都跳过 RBAC 校验
  • string:只匹配一个请求方法,例如 POST
  • array:匹配多个请求方法,例如 ['GET', 'POST']

系统会统一把请求方法转成大写后再进行匹配。

优先级

方法上的 PermissionExempt 优先级高于控制器类上的 PermissionExempt

例如:

php
use Catch\Attributes\PermissionExempt;

#[PermissionExempt]
class DemoController
{
    #[PermissionExempt('POST')]
    public function callback()
    {
    }
}

这里 callback() 只会在 POST 请求时跳过 RBAC 校验,GET 请求会继续进入正常权限判断。

生效边界

  • PermissionExempt 影响的是 RBAC 权限校验
  • 登录认证中间件依然生效
  • demo 环境写请求保护依然生效
  • GET 默认放行规则依然生效

这意味着接口即使声明了 PermissionExempt,依然需要先通过认证链路。demo 环境下的写请求依然会被拦截。

权限配置

了解中间件机制后,重点需要掌握权限的数据结构组成。前后端分离项目的权限配置相比传统渲染项目更为复杂,建议先熟悉 Vue 路由相关知识。在权限管理/菜单管理页面点击新增,可看到权限配置界面

pSl4dVP.pngCatchAdmin 将权限分为三种类型

  • 目录 目录仅仅就是一级菜单

  • 菜单 菜单就是主要的页面

  • 按钮 每个页面的操作,每个按钮都对应后端的控制的一个 action,这个非常重要

  • 路由 Path 对应前端 vue 路由的 path

  • 组件 对应前端 vue 路由的 component

    • 目录类型一般都是选择 Layout 组件
    • 菜单类型则是选择对应页面的组件

传统 Laravel 项目通过 Controller 实现页面和操作的权限控制。前后端分离项目中,页面渲染交由前端处理,但数据操作仍由后端控制,因此 RBAC 权限系统主要负责 API 访问控制。后端重点关注按钮类型权限,即对控制器 action 方法的访问控制。 因此需要为控制器的每个 action 操作配置相应的权限标识,实现精细化权限控制。

权限判断

CatchAdmin 专业版采用模块化架构,权限标识格式规范如下

module@controller@action

例如权限模块的角色列表操作,权限验证标识格式示例

php
Modules\permissions\Http\Controller\RolesController@index

当前用户是否有权限

php
// 验证当前用户是否具有指定权限
Auth::user()->can(string $permission = null);
  • permission 参数格式为 module@controller@action,例如 permissions@Roles@index

用户的权限

php
// 获取用户的所有权限列表
/*@var Model\Roles $user*/
$user->withPermissions()->permissions;

角色权限

php
/*@var Model\Roles $role*/
$role->getPermissions()