权限管理是Web应用中的核心功能之一。本文将详细介绍如何使用ThinkPHP 6.x框架实现一个完整的RBAC(基于角色的权限控制)系统,包含用户、角色、权限的多层级管理。
系统设计思路
我们将创建一个包含以下核心功能的权限管理系统:
- 用户管理:系统用户账户的CRUD操作
- 角色管理:定义不同角色并分配权限
- 权限管理:创建系统操作权限点
- 菜单管理:动态生成权限控制的导航菜单
- 中间件验证:使用中间件进行权限验证
数据库设计
数据表结构
-- 用户表 CREATE TABLE `user` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名', `password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码', `email` varchar(100) DEFAULT '' COMMENT '邮箱', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1正常,0禁用', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', `update_time` int(11) DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 角色表 CREATE TABLE `role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '角色名称', `description` varchar(255) DEFAULT '' COMMENT '角色描述', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1正常,0禁用', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; -- 权限表 CREATE TABLE `permission` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '权限名称', `path` varchar(100) NOT NULL DEFAULT '' COMMENT '权限路径', `type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '类型:1菜单,2操作', `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父级ID', `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序', `icon` varchar(50) DEFAULT '' COMMENT '图标', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1正常,0禁用', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表'; -- 用户角色关联表 CREATE TABLE `user_role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '用户ID', `role_id` int(11) NOT NULL COMMENT '角色ID', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `role_id` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表'; -- 角色权限关联表 CREATE TABLE `role_permission` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `role_id` int(11) NOT NULL COMMENT '角色ID', `permission_id` int(11) NOT NULL COMMENT '权限ID', `create_time` int(11) DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), KEY `role_id` (`role_id`), KEY `permission_id` (`permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表';
核心功能实现
1. 模型定义
用户模型 (app/model/User.php)
<?php namespace appmodel; use thinkModel; use thinkmodelconcernSoftDelete; class User extends Model { use SoftDelete; protected $name = 'user'; protected $autoWriteTimestamp = true; // 设置密码加密 public function setPasswordAttr($value) { return password_hash($value, PASSWORD_DEFAULT); } // 用户角色关联 public function roles() { return $this->belongsToMany('Role', 'UserRole'); } // 检查用户是否有指定权限 public function hasPermission($permissionPath) { // 超级管理员拥有所有权限 if ($this->id === 1) { return true; } $roles = $this->roles()->with('permissions')->select(); foreach ($roles as $role) { foreach ($role->permissions as $permission) { if ($permission->path === $permissionPath && $permission->status === 1) { return true; } } } return false; } } ?>
角色模型 (app/model/Role.php)
<?php namespace appmodel; use thinkModel; class Role extends Model { protected $name = 'role'; protected $autoWriteTimestamp = true; // 角色权限关联 public function permissions() { return $this->belongsToMany('Permission', 'RolePermission'); } // 获取角色权限ID数组 public function getPermissionIds() { return $this->permissions()->column('permission_id'); } } ?>
权限模型 (app/model/Permission.php)
<?php namespace appmodel; use thinkModel; class Permission extends Model { protected $name = 'permission'; protected $autoWriteTimestamp = true; // 获取树形权限结构 public static function getTree($pid = 0) { $permissions = self::where('pid', $pid) ->where('status', 1) ->order('sort', 'asc') ->select(); if ($permissions->isEmpty()) { return []; } foreach ($permissions as &$permission) { $children = self::getTree($permission->id); if (!empty($children)) { $permission->children = $children; } } return $permissions->toArray(); } } ?>
2. 权限验证中间件
(app/middleware/PermissionCheck.php)
<?php namespace appmiddleware; use thinkfacadeRequest; use thinkfacadeSession; class PermissionCheck { public function handle($request, Closure $next) { // 排除登录页面和登录操作 $excludeRoutes = [ 'admin/login/index', 'admin/login/login', 'admin/login/logout' ]; $currentRoute = strtolower($request->controller() . '/' . $request->action()); if (in_array($currentRoute, $excludeRoutes)) { return $next($request); } // 检查用户是否登录 $user = Session::get('admin_user'); if (!$user) { return redirect('/admin/login/index'); } // 检查权限 $permissionPath = strtolower($request->module() . '/' . $request->controller() . '/' . $request->action()); if (!$user->hasPermission($permissionPath)) { if ($request->isAjax()) { return json(['code' => 403, 'msg' => '没有权限操作']); } else { return view('admin@public/error', ['msg' => '没有权限操作']); } } return $next($request); } } ?>
3. 权限管理控制器
(app/controller/admin/PermissionController.php)
<?php namespace appcontrolleradmin; use appBaseController; use appmodelPermission; use thinkfacadeView; class PermissionController extends BaseController { // 权限列表 public function index() { $permissions = Permission::getTree(); View::assign('permissions', $permissions); return View::fetch(); } // 添加权限 public function add() { if ($this->request->isPost()) { $data = $this->request->post(); $validate = new appvalidatePermission(); if (!$validate->check($data)) { return json(['code' => 0, 'msg' => $validate->getError()]); } try { $permission = Permission::create($data); return json(['code' => 1, 'msg' => '添加成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '添加失败: ' . $e->getMessage()]); } } $parentPermissions = Permission::where('pid', 0) ->where('status', 1) ->select(); View::assign('parentPermissions', $parentPermissions); return View::fetch(); } // 编辑权限 public function edit($id) { $permission = Permission::find($id); if (!$permission) { return json(['code' => 0, 'msg' => '权限不存在']); } if ($this->request->isPost()) { $data = $this->request->post(); $validate = new appvalidatePermission(); if (!$validate->check($data)) { return json(['code' => 0, 'msg' => $validate->getError()]); } try { $permission->save($data); return json(['code' => 1, 'msg' => '更新成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '更新失败: ' . $e->getMessage()]); } } $parentPermissions = Permission::where('pid', 0) ->where('status', 1) ->where('id', '', $id) ->select(); View::assign([ 'permission' => $permission, 'parentPermissions' => $parentPermissions ]); return View::fetch(); } // 删除权限 public function delete($id) { $permission = Permission::find($id); if (!$permission) { return json(['code' => 0, 'msg' => '权限不存在']); } // 检查是否有子权限 $childCount = Permission::where('pid', $id)->count(); if ($childCount > 0) { return json(['code' => 0, 'msg' => '请先删除子权限']); } try { $permission->delete(); return json(['code' => 1, 'msg' => '删除成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '删除失败: ' . $e->getMessage()]); } } } ?>
4. 角色管理控制器
(app/controller/admin/RoleController.php)
<?php namespace appcontrolleradmin; use appBaseController; use appmodelRole; use appmodelPermission; use thinkfacadeView; class RoleController extends BaseController { // 角色列表 public function index() { $roles = Role::where('status', 1)->select(); View::assign('roles', $roles); return View::fetch(); } // 添加角色 public function add() { if ($this->request->isPost()) { $data = $this->request->post(); $validate = new appvalidateRole(); if (!$validate->check($data)) { return json(['code' => 0, 'msg' => $validate->getError()]); } try { $role = Role::create($data); // 分配权限 if (!empty($data['permission_ids'])) { $role->permissions()->saveAll($data['permission_ids']); } return json(['code' => 1, 'msg' => '添加成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '添加失败: ' . $e->getMessage()]); } } // 获取所有权限 $permissions = Permission::getTree(); View::assign('permissions', $permissions); return View::fetch(); } // 编辑角色 public function edit($id) { $role = Role::find($id); if (!$role) { return json(['code' => 0, 'msg' => '角色不存在']); } if ($this->request->isPost()) { $data = $this->request->post(); $validate = new appvalidateRole(); if (!$validate->check($data)) { return json(['code' => 0, 'msg' => $validate->getError()]); } try { $role->save($data); // 更新权限 if (isset($data['permission_ids'])) { $role->permissions()->detach(); if (!empty($data['permission_ids'])) { $role->permissions()->saveAll($data['permission_ids']); } } return json(['code' => 1, 'msg' => '更新成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '更新失败: ' . $e->getMessage()]); } } // 获取所有权限 $permissions = Permission::getTree(); // 获取角色已有权限ID $rolePermissionIds = $role->getPermissionIds(); View::assign([ 'role' => $role, 'permissions' => $permissions, 'rolePermissionIds' => $rolePermissionIds ]); return View::fetch(); } // 删除角色 public function delete($id) { $role = Role::find($id); if (!$role) { return json(['code' => 0, 'msg' => '角色不存在']); } // 检查是否有用户使用此角色 $userCount = $role->users()->count(); if ($userCount > 0) { return json(['code' => 0, 'msg' => '有用户使用此角色,无法删除']); } try { // 删除角色权限关联 $role->permissions()->detach(); $role->delete(); return json(['code' => 1, 'msg' => '删除成功']); } catch (Exception $e) { return json(['code' => 0, 'msg' => '删除失败: ' . $e->getMessage()]); } } } ?>
5. 动态菜单生成
创建菜单助手函数 (app/common.php)
<?php // 获取用户有权限的菜单 function get_admin_menu($user) { // 超级管理员获取所有菜单 if ($user->id === 1) { $menus = appmodelPermission::where('type', 1) ->where('status', 1) ->order('sort', 'asc') ->select(); } else { // 获取用户角色 $roles = $user->roles; $permissionIds = []; foreach ($roles as $role) { $rolePermissionIds = $role->permissions() ->where('type', 1) ->where('status', 1) ->column('permission.id'); $permissionIds = array_merge($permissionIds, $rolePermissionIds); } $permissionIds = array_unique($permissionIds); if (empty($permissionIds)) { return []; } $menus = appmodelPermission::where('id', 'in', $permissionIds) ->where('type', 1) ->where('status', 1) ->order('sort', 'asc') ->select(); } return array_to_tree($menus->toArray()); } // 数组转树形结构 function array_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'children', $root = 0) { $tree = []; $refer = []; foreach ($list as $key => $data) { $refer[$data[$pk]] = &$list[$key]; } foreach ($list as $key => $data) { $parentId = $data[$pid]; if ($root == $parentId) { $tree[] = &$list[$key]; } else { if (isset($refer[$parentId])) { $parent = &$refer[$parentId]; $parent[$child][] = &$list[$key]; } } } return $tree; } ?>
6. 中间件注册与使用
全局中间件注册 (app/middleware.php)
<?php return [ // 全局中间件 appmiddlewarePermissionCheck::class, ]; ?>
路由配置 (route/app.php)
<?php use thinkfacadeRoute; // 后台路由组 Route::group('admin', function () { // 登录路由 Route::get('login/index', 'admin/Login/index'); Route::post('login/login', 'admin/Login/login'); Route::get('login/logout', 'admin/Login/logout'); // 权限管理 Route::get('permission/index', 'admin/Permission/index'); Route::get('permission/add', 'admin/Permission/add'); Route::post('permission/add', 'admin/Permission/add'); Route::get('permission/edit/:id', 'admin/Permission/edit'); Route::post('permission/edit/:id', 'admin/Permission/edit'); Route::post('permission/delete/:id', 'admin/Permission/delete'); // 角色管理 Route::get('role/index', 'admin/Role/index'); Route::get('role/add', 'admin/Role/add'); Route::post('role/add', 'admin/Role/add'); Route::get('role/edit/:id', 'admin/Role/edit'); Route::post('role/edit/:id', 'admin/Role/edit'); Route::post('role/delete/:id', 'admin/Role/delete'); // 用户管理 Route::get('user/index', 'admin/User/index'); Route::get('user/add', 'admin/User/add'); Route::post('user/add', 'admin/User/add'); Route::get('user/edit/:id', 'admin/User/edit'); Route::post('user/edit/:id', 'admin/User/edit'); Route::post('user/delete/:id', 'admin/User/delete'); })->prefix('admin/'); ?>
系统特点与优势
- 灵活的权限控制:支持菜单权限和操作权限的精细控制
- 多层级结构:支持无限层级的权限和菜单结构
- 中间件验证:使用中间件统一处理权限验证逻辑
- 动态菜单生成:根据用户权限动态生成导航菜单
- 易于扩展:模块化设计,方便添加新的权限控制点
- ThinkPHP最佳实践:充分利用ThinkPHP 6.x的新特性
实际应用建议
这个权限管理系统可以应用于多种场景:
- 企业后台管理系统:根据不同部门角色分配不同权限
- 电商平台:区分管理员、运营、客服等角色权限
- SaaS应用:为不同客户分配不同的功能权限
- 内容管理系统:控制编辑、审核、发布等权限
进一步优化方向
要使这个权限管理系统更加完善,可以考虑以下优化:
- 添加操作日志记录,跟踪用户权限使用情况
- 实现数据权限控制,限制用户只能访问特定范围的数据
- 添加权限缓存机制,提高权限验证性能
- 实现权限导入导出功能,方便权限配置迁移
- 添加权限模板功能,快速创建角色权限组
总结
通过本教程,我们实现了一个基于ThinkPHP 6.x的完整RBAC权限管理系统。这个系统包含了用户管理、角色管理、权限管理和动态菜单生成等核心功能,采用了中间件进行统一的权限验证。
该系统设计遵循了ThinkPHP的最佳实践,充分利用了模型关联、中间件、验证器等特性,代码结构清晰,易于维护和扩展。您可以根据实际项目需求,在此基础上进行进一步的定制和优化。
掌握权限管理系统的实现对于开发企业级应用至关重要,这个教程为您提供了一个坚实的基础,帮助您构建安全、灵活的权限控制系统。