一、RBAC 模型简介

1.1 什么是 RBAC 模型

RBAC(Role-Based Access Control)即基于角色的访问控制,它是一种通过对角色的权限分配来实现对用户访问权限管理的方法。在一个系统中,不同的用户可能具有不同的角色,比如管理员、普通用户等,每个角色被赋予特定的权限,用户通过拥有的角色来获得相应的权限。

1.2 RBAC 模型的基本组成

  • 用户(User):系统的使用者,例如在一个电商系统中,买家和卖家都是用户。
  • 角色(Role):具有一定权限的集合,比如在一个企业管理系统中,有经理、员工等角色。
  • 权限(Permission):对系统资源的操作许可,比如在文件管理系统中,读取、写入、删除文件就是不同的权限。

二、ThinkPHP 中 RBAC 模型的落地

2.1 数据库设计

  • 用户表(user)

    // 假设使用 MySQL 数据库,以下是用户表结构示例
    CREATE TABLE `user` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `username` varchar(50) NOT NULL,
        `password` varchar(100) NOT NULL,
        `role_id` int(11) NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:这里的 role_id 用于关联角色表,通过这个字段可以知道用户所属的角色。

  • 角色表(role)

    CREATE TABLE `role` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `role_name` varchar(50) NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:存储角色的名称等信息。

  • 权限表(permission)

    CREATE TABLE `permission` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `permission_name` varchar(50) NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:记录各种权限的名称。

  • 角色 - 权限关系表(role_permission)

    CREATE TABLE `role_permission` (
        `role_id` int(11) NOT NULL,
        `permission_id` int(11) NOT NULL,
        PRIMARY KEY (`role_id`, `permission_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:通过这个表来建立角色和权限之间的多对多关系。

2.2 模型创建

在 ThinkPHP 中创建相应的模型类。

  • User 模型

    <?php
    namespace app\model;
    use think\Model;
    
    class User extends Model
    {
        protected $table = 'user';
    
        // 关联角色模型
        public function role()
        {
            return $this->belongsTo('Role');
        }
    }
    

    // 注释:通过 role 方法可以获取用户所属的角色信息。

  • Role 模型

    <?php
    namespace app\model;
    use think\Model;
    
    class Role extends Model
    {
        protected $table = 'role';
    
        // 关联权限模型,多对多关系
        public function permissions()
        {
            return $this->belongsToMany('Permission', 'role_permission', 'permission_id', 'role_id');
        }
    }
    

    // 注释:通过 permissions 方法可以获取角色所拥有的权限集合。

  • Permission 模型

    <?php
    namespace app\model;
    use think\Model;
    
    class Permission extends Model
    {
        protected $table = 'permission';
    }
    

2.3 权限验证

在控制器中进行权限验证。

<?php
namespace app\controller;
use app\model\User;
use think\Controller;

class Index extends Controller
{
    public function index()
    {
        // 获取当前登录用户
        $user = User::find(1); // 这里假设用户 ID 为 1
        if ($user) {
            // 获取用户角色
            $role = $user->role;
            if ($role) {
                // 获取角色权限
                $permissions = $role->permissions;
                // 假设这里有一个权限名称为 'view_index'
                $hasPermission = false;
                foreach ($permissions as $permission) {
                    if ($permission->permission_name === 'view_index') {
                        $hasPermission = true;
                        break;
                    }
                }
                if ($hasPermission) {
                    return '你有权限访问该页面';
                } else {
                    return '你没有权限访问该页面';
                }
            }
        }
        return '用户未登录或不存在';
    }
}

// 注释:这段代码首先获取当前登录用户,然后通过用户关联的角色获取角色的权限,最后判断用户是否有访问当前页面的权限。

三、RBAC 模型的扩展方案

3.1 基于部门的权限扩展

  • 部门表(department)

    CREATE TABLE `department` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `department_name` varchar(50) NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:用于存储部门信息。

  • 用户 - 部门关系表(user_department)

    CREATE TABLE `user_department` (
        `user_id` int(11) NOT NULL,
        `department_id` int(11) NOT NULL,
        PRIMARY KEY (`user_id`, `department_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:建立用户和部门之间的多对多关系。

  • 扩展权限验证逻辑 在原来的权限验证基础上,加入部门相关的权限判断。

<?php
namespace app\controller;
use app\model\User;
use think\Controller;

class Index extends Controller
{
    public function index()
    {
        // 获取当前登录用户
        $user = User::find(1); // 这里假设用户 ID 为 1
        if ($user) {
            // 获取用户角色
            $role = $user->role;
            if ($role) {
                // 获取角色权限
                $permissions = $role->permissions;
                // 假设这里有一个权限名称为 'view_index'
                $hasPermission = false;
                foreach ($permissions as $permission) {
                    if ($permission->permission_name === 'view_index') {
                        $hasPermission = true;
                        break;
                    }
                }
                // 加入部门权限判断
                $departments = $user->departments;
                foreach ($departments as $department) {
                    // 假设部门也有相关权限存储在 department_permission 表中
                    $departmentPermissions = $department->permissions;
                    foreach ($departmentPermissions as $departmentPermission) {
                        if ($departmentPermission->permission_name === 'view_index') {
                            $hasPermission = true;
                            break 2;
                        }
                    }
                }
                if ($hasPermission) {
                    return '你有权限访问该页面';
                } else {
                    return '你没有权限访问该页面';
                }
            }
        }
        return '用户未登录或不存在';
    }
}

// 注释:这里在角色权限验证的基础上,又加入了部门权限的验证,如果用户所属部门有相应权限,也认为用户有权限访问。

3.2 动态权限分配

  • 创建动态权限表(dynamic_permission)

    CREATE TABLE `dynamic_permission` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `user_id` int(11) NOT NULL,
        `permission_name` varchar(50) NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    // 注释:用于存储动态分配给用户的权限。

  • 实现动态权限分配逻辑 在用户登录或其他操作时,可以根据业务需求动态分配权限。

<?php
namespace app\controller;
use app\model\User;
use think\Controller;

class Index extends Controller
{
    public function index()
    {
        // 获取当前登录用户
        $user = User::find(1); // 这里假设用户 ID 为 1
        if ($user) {
            // 先检查角色和部门权限
            $role = $user->role;
            $departments = $user->departments;
            $hasPermission = false;
            if ($role) {
                $permissions = $role->permissions;
                foreach ($permissions as $permission) {
                    if ($permission->permission_name === 'view_index') {
                        $hasPermission = true;
                        break;
                    }
                }
            }
            if (!$hasPermission && $departments) {
                foreach ($departments as $department) {
                    $departmentPermissions = $department->permissions;
                    foreach ($departmentPermissions as $departmentPermission) {
                        if ($departmentPermission->permission_name === 'view_index') {
                            $hasPermission = true;
                            break 2;
                        }
                    }
                }
            }
            // 再检查动态权限
            $dynamicPermissions = $user->dynamicPermissions;
            foreach ($dynamicPermissions as $dynamicPermission) {
                if ($dynamicPermission->permission_name === 'view_index') {
                    $hasPermission = true;
                    break;
                }
            }
            if ($hasPermission) {
                return '你有权限访问该页面';
            } else {
                return '你没有权限访问该页面';
            }
        }
        return '用户未登录或不存在';
    }
}

// 注释:这段代码在原来的权限验证基础上,又加入了动态权限的验证,使得权限分配更加灵活。

四、应用场景

4.1 企业管理系统

在企业管理系统中,不同部门的员工可能具有不同的权限。例如,财务部门的员工可以查看和修改财务相关的报表,而销售部门的员工只能查看销售数据。通过 RBAC 模型,可以很方便地为不同部门的员工分配相应的角色和权限,同时可以根据部门的特点进行权限扩展。

4.2 电商系统

在电商系统中,买家和卖家具有不同的权限。买家可以浏览商品、下单购买等,而卖家可以管理店铺、发布商品等。通过 RBAC 模型,可以清晰地划分不同用户角色的权限,并且可以根据业务需求进行动态权限分配,比如对于一些特殊的促销活动,为特定的用户群体分配额外的权限。

五、技术优缺点

5.1 优点

  • 管理方便:通过角色来管理权限,而不是直接对用户进行权限分配,大大减少了管理的复杂度。
  • 灵活性高:可以很方便地进行权限扩展,如基于部门的权限扩展和动态权限分配。
  • 安全性强:明确了不同用户的权限,减少了越权操作的可能性。

5.2 缺点

  • 角色数量过多可能导致混乱:如果系统中角色数量过多,可能会导致权限分配不清晰,难以管理。
  • 初期配置工作量较大:需要花费一定的时间来设计数据库结构和配置角色权限。

六、注意事项

6.1 角色和权限的合理划分

在设计角色和权限时,要充分考虑业务需求,确保角色和权限的划分合理,避免出现权限漏洞或过于复杂的情况。

6.2 数据一致性

在进行权限分配和修改时,要注意保持数据的一致性,特别是在多对多关系的表中,要确保数据的准确性。

6.3 系统性能

随着系统用户和权限数量的增加,权限验证的性能可能会受到影响。可以考虑使用缓存等技术来提高性能。

七、文章总结

本文介绍了 ThinkPHP 中权限控制的 RBAC 模型的落地与扩展方案。首先介绍了 RBAC 模型的基本概念,然后详细说明了在 ThinkPHP 中如何进行数据库设计、模型创建和权限验证。接着介绍了基于部门的权限扩展和动态权限分配的方案,并分析了其应用场景、技术优缺点和注意事项。通过合理使用 RBAC 模型及其扩展方案,可以有效地管理系统的权限,提高系统的安全性和灵活性。