原创作者:ThinkPHP技术专家 | 发布日期:2023年11月
一、企业级RBAC权限系统架构设计
RBAC(Role-Based Access Control)是基于角色的访问控制模型,在企业级应用中具有重要地位。ThinkPHP 6.1提供了完善的中间件、验证器和服务容器支持,为构建健壮的权限系统奠定了基础。
1.1 核心架构组件
- 用户管理模块:用户信息、角色分配、状态管理
- 角色管理模块:角色定义、权限绑定、层级关系
- 权限管理模块:菜单权限、操作权限、数据权限
- 日志审计模块:操作日志、登录日志、安全审计
1.2 系统流程设计
用户登录 → 身份验证 → 获取角色 → 加载权限 → 权限验证 → 访问控制 ↓ 日志记录 ← 操作执行 ← 数据过滤 ← 菜单渲染 ← 权限缓存
二、数据库设计与性能优化
2.1 核心数据表结构
// 用户表
CREATE TABLE `rbac_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '密码',
`realname` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`mobile` varchar(20) DEFAULT NULL COMMENT '手机号',
`status` tinyint(1) 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 `rbac_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '角色名称',
`description` varchar(255) DEFAULT NULL COMMENT '角色描述',
`status` tinyint(1) DEFAULT '1' COMMENT '状态:1正常 0禁用',
`create_time` int(11) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
// 权限表
CREATE TABLE `rbac_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '权限名称',
`path` varchar(255) DEFAULT NULL COMMENT '权限路径',
`type` tinyint(1) DEFAULT '1' COMMENT '类型:1菜单 2操作',
`parent_id` int(11) DEFAULT '0' COMMENT '父级ID',
`sort` int(11) DEFAULT '0' COMMENT '排序',
`icon` varchar(50) DEFAULT NULL COMMENT '图标',
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
`create_time` int(11) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';
// 用户角色关联表
CREATE TABLE `rbac_user_role` (
`id` int(11) 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 `rbac_role_permission` (
`id` int(11) 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='角色权限关联表';
2.2 模型关系定义
// app/model/User.php
namespace appmodel;
use thinkModel;
class User extends Model
{
protected $table = 'rbac_user';
// 用户角色关联
public function roles()
{
return $this->belongsToMany(Role::class, 'rbac_user_role', 'role_id', 'user_id');
}
// 密码自动加密
public function setPasswordAttr($value)
{
return password_hash($value, PASSWORD_DEFAULT);
}
}
// app/model/Role.php
class Role extends Model
{
protected $table = 'rbac_role';
// 角色权限关联
public function permissions()
{
return $this->belongsToMany(Permission::class, 'rbac_role_permission', 'permission_id', 'role_id');
}
// 角色用户关联
public function users()
{
return $this->belongsToMany(User::class, 'rbac_user_role', 'user_id', 'role_id');
}
}
// app/model/Permission.php
class Permission extends Model
{
protected $table = 'rbac_permission';
// 权限树形结构
public function children()
{
return $this->hasMany(Permission::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(Permission::class, 'parent_id');
}
}
三、中间件权限验证实现
3.1 权限验证中间件
// app/middleware/AuthMiddleware.php
namespace appmiddleware;
use thinkfacadeSession;
use thinkfacadeRequest;
class AuthMiddleware
{
public function handle($request, Closure $next)
{
// 检查用户是否登录
$user = Session::get('user');
if (!$user) {
if ($request->isAjax()) {
return json(['code' => 401, 'msg' => '请先登录']);
}
return redirect('/login');
}
// 权限验证
if (!$this->checkPermission($request, $user)) {
if ($request->isAjax()) {
return json(['code' => 403, 'msg' => '权限不足']);
}
return view('public/403');
}
return $next($request);
}
/**
* 权限检查
*/
private function checkPermission($request, $user)
{
// 超级管理员拥有所有权限
if ($user['is_super'] == 1) {
return true;
}
$currentPath = $request->controller() . '/' . $request->action();
$userPermissions = Session::get('user_permissions');
// 检查权限路径
foreach ($userPermissions as $permission) {
if ($permission['path'] == $currentPath) {
return true;
}
}
return false;
}
}
3.2 中间件注册配置
// app/middleware.php
return [
// 全局中间件
appmiddlewareAuthMiddleware::class => [
'except' => [
'login/index',
'login/check',
'public/*'
]
],
// 路由中间件
'auth' => appmiddlewareAuthMiddleware::class
];
四、服务层业务逻辑封装
4.1 权限服务类
// app/service/PermissionService.php
namespace appservice;
use thinkfacadeDb;
use thinkfacadeCache;
class PermissionService
{
/**
* 获取用户权限列表
*/
public function getUserPermissions($userId)
{
$cacheKey = 'user_permissions_' . $userId;
$permissions = Cache::get($cacheKey);
if (!$permissions) {
$permissions = Db::name('rbac_permission')
->alias('p')
->join('rbac_role_permission rp', 'p.id = rp.permission_id')
->join('rbac_user_role ur', 'rp.role_id = ur.role_id')
->where('ur.user_id', $userId)
->where('p.status', 1)
->field('p.id, p.name, p.path, p.type, p.parent_id, p.icon')
->select()
->toArray();
Cache::set($cacheKey, $permissions, 3600);
}
return $permissions;
}
/**
* 构建权限树形结构
*/
public function buildPermissionTree($permissions, $parentId = 0)
{
$tree = [];
foreach ($permissions as $permission) {
if ($permission['parent_id'] == $parentId) {
$children = $this->buildPermissionTree($permissions, $permission['id']);
if ($children) {
$permission['children'] = $children;
}
$tree[] = $permission;
}
}
return $tree;
}
/**
* 检查用户权限
*/
public function checkUserPermission($userId, $permissionPath)
{
$permissions = $this->getUserPermissions($userId);
foreach ($permissions as $permission) {
if ($permission['path'] == $permissionPath) {
return true;
}
}
return false;
}
}
4.2 用户服务类
// app/service/UserService.php
namespace appservice;
use thinkfacadeDb;
use thinkfacadeSession;
class UserService
{
/**
* 用户登录
*/
public function login($username, $password)
{
$user = Db::name('rbac_user')
->where('username', $username)
->where('status', 1)
->find();
if (!$user) {
throw new Exception('用户不存在或已被禁用');
}
if (!password_verify($password, $user['password'])) {
throw new Exception('密码错误');
}
// 获取用户角色和权限
$permissionService = new PermissionService();
$userPermissions = $permissionService->getUserPermissions($user['id']);
// 存储会话信息
Session::set('user', [
'id' => $user['id'],
'username' => $user['username'],
'realname' => $user['realname'],
'is_super' => $user['is_super'] ?? 0
]);
Session::set('user_permissions', $userPermissions);
// 记录登录日志
$this->recordLoginLog($user['id']);
return true;
}
/**
* 记录登录日志
*/
private function recordLoginLog($userId)
{
Db::name('login_log')->insert([
'user_id' => $userId,
'login_ip' => request()->ip(),
'login_time' => time(),
'user_agent' => request()->header('user-agent')
]);
}
}
五、前后端权限集成方案
5.1 控制器权限验证
// app/controller/Admin.php
namespace appcontroller;
use appBaseController;
use thinkfacadeView;
use appservicePermissionService;
class Admin extends BaseController
{
protected $permissionService;
public function initialize()
{
$this->permissionService = new PermissionService();
}
/**
* 获取用户菜单
*/
public function getMenu()
{
$userId = session('user.id');
$permissions = $this->permissionService->getUserPermissions($userId);
$menuTree = $this->permissionService->buildPermissionTree($permissions);
return json([
'code' => 200,
'data' => $menuTree
]);
}
/**
* 用户管理页面
*/
public function user()
{
// 权限验证
if (!$this->checkPermission('admin/user')) {
return $this->error('权限不足');
}
return View::fetch('admin/user');
}
/**
* 权限检查封装
*/
protected function checkPermission($permissionPath)
{
$userId = session('user.id');
return $this->permissionService->checkUserPermission($userId, $permissionPath);
}
}
5.2 前端权限控制
// 前端JavaScript权限控制
class PermissionManager {
constructor() {
this.permissions = [];
this.loadPermissions();
}
// 加载权限列表
async loadPermissions() {
try {
const response = await fetch('/admin/getMenu');
const result = await response.json();
if (result.code === 200) {
this.permissions = result.data;
this.renderMenu();
}
} catch (error) {
console.error('加载权限失败:', error);
}
}
// 渲染菜单
renderMenu() {
const menuContainer = document.getElementById('sidebar-menu');
menuContainer.innerHTML = this.buildMenuHTML(this.permissions);
}
// 构建菜单HTML
buildMenuHTML(permissions, level = 0) {
let html = '';
permissions.forEach(permission => {
if (permission.type === 1) { // 菜单类型
const hasChildren = permission.children && permission.children.length > 0;
html += `
${permission.name}
${hasChildren ? this.buildMenuHTML(permission.children, level + 1) : ''}
`;
}
});
return level === 0 ? ` ` : ` `;
}
// 检查操作权限
checkActionPermission(actionPath) {
return this.permissions.some(permission =>
permission.path === actionPath && permission.type === 2
);
}
}
// 初始化权限管理器
document.addEventListener('DOMContentLoaded', function() {
window.permissionManager = new PermissionManager();
});
六、安全防护与性能优化
6.1 安全防护措施
// app/service/SecurityService.php
namespace appservice;
use thinkfacadeDb;
use thinkfacadeRequest;
class SecurityService
{
/**
* IP访问频率限制
*/
public function checkIpRateLimit($ip, $maxAttempts = 10, $decayMinutes = 1)
{
$cacheKey = 'login_attempts_' . md5($ip);
$attempts = cache($cacheKey) ?: 0;
if ($attempts >= $maxAttempts) {
throw new Exception('访问过于频繁,请稍后重试');
}
cache($cacheKey, $attempts + 1, $decayMinutes * 60);
}
/**
* 密码强度验证
*/
public function validatePasswordStrength($password)
{
if (strlen($password) < 8) {
throw new Exception('密码长度至少8位');
}
if (!preg_match('/[a-z]/', $password)) {
throw new Exception('密码必须包含小写字母');
}
if (!preg_match('/[A-Z]/', $password)) {
throw new Exception('密码必须包含大写字母');
}
if (!preg_match('/[0-9]/', $password)) {
throw new Exception('密码必须包含数字');
}
return true;
}
/**
* 会话安全检测
*/
public function checkSessionSecurity()
{
$userAgent = Request::header('user-agent');
$sessionUserAgent = session('user_agent');
if (!$sessionUserAgent) {
session('user_agent', $userAgent);
return true;
}
if ($sessionUserAgent !== $userAgent) {
session(null);
throw new Exception('会话异常,请重新登录');
}
return true;
}
}
6.2 性能优化策略
// 权限缓存优化
class OptimizedPermissionService extends PermissionService
{
/**
* 批量获取用户权限(减少数据库查询)
*/
public function getBatchUserPermissions($userIds)
{
$cacheKeys = array_map(function($userId) {
return 'user_permissions_' . $userId;
}, $userIds);
$cachedPermissions = Cache::getMultiple($cacheKeys);
$result = [];
$needQueryIds = [];
foreach ($userIds as $index => $userId) {
if ($cachedPermissions[$cacheKeys[$index]] !== null) {
$result[$userId] = $cachedPermissions[$cacheKeys[$index]];
} else {
$needQueryIds[] = $userId;
}
}
if (!empty($needQueryIds)) {
$dbPermissions = $this->getPermissionsFromDatabase($needQueryIds);
foreach ($dbPermissions as $userId => $permissions) {
$result[$userId] = $permissions;
Cache::set('user_permissions_' . $userId, $permissions, 3600);
}
}
return $result;
}
private function getPermissionsFromDatabase($userIds)
{
// 批量查询数据库逻辑
$permissions = Db::name('rbac_permission')
->alias('p')
->join('rbac_role_permission rp', 'p.id = rp.permission_id')
->join('rbac_user_role ur', 'rp.role_id = ur.role_id')
->where('ur.user_id', 'in', $userIds)
->where('p.status', 1)
->field('ur.user_id, p.id, p.name, p.path, p.type, p.parent_id, p.icon')
->select()
->toArray();
$result = [];
foreach ($permissions as $permission) {
$result[$permission['user_id']][] = $permission;
}
return $result;
}
}
项目总结与扩展
本文详细介绍了基于ThinkPHP 6.1的企业级RBAC权限管理系统的完整开发流程。从数据库设计到中间件开发,从服务层封装到前后端集成,我们构建了一个功能完备、安全可靠的权限控制系统。
核心技术亮点:
- 基于ThinkPHP 6.1的现代化架构设计
- 完整的RBAC权限模型实现
- 中间件驱动的权限验证机制
- 服务层业务逻辑封装与复用
- 前后端一体化的权限控制方案
- 多层次的安全防护体系
扩展建议:
- 集成JWT令牌认证支持API访问
- 实现数据级权限控制(行级、列级权限)
- 添加权限变更审计和版本控制
- 开发可视化权限配置界面
- 支持多租户权限隔离
本系统为企业级应用提供了坚实的权限管理基础,可根据具体业务需求进行灵活扩展和定制。