从零构建高性能后台权限管理系统的完整方案
一、RBAC权限模型核心设计
基于角色的访问控制(RBAC)是现代后台系统的标配功能,我们采用五表结构设计:
1. 数据库表结构
# 用户表
CREATE TABLE `admin_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名',
`password` varchar(255) NOT NULL COMMENT '密码',
`status` tinyint(1) DEFAULT '1' COMMENT '状态',
`create_time` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 角色表
CREATE TABLE `admin_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '角色名称',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`status` tinyint(1) DEFAULT '1' COMMENT '状态'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 用户角色关联表
CREATE TABLE `admin_user_role` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 权限节点表
CREATE TABLE `admin_node` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '节点名称',
`route` varchar(128) NOT NULL COMMENT '路由规则',
`type` tinyint(1) DEFAULT '1' COMMENT '类型 1:菜单 2:操作',
`pid` int(11) DEFAULT '0' COMMENT '父级ID',
`sort` int(11) DEFAULT '0' COMMENT '排序'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# 角色权限关联表
CREATE TABLE `admin_role_node` (
`role_id` int(11) NOT NULL,
`node_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
二、核心功能实现
1. 权限验证中间件
<?php
namespace appadminmiddleware;
use thinkfacadeSession;
class AuthCheck
{
public function handle($request, Closure $next)
{
// 排除登录页
if (!preg_match('/login/', $request->pathinfo())) {
// 验证登录状态
if (!Session::has('admin_user')) {
return redirect('/admin/login');
}
// 超级管理员跳过验证
if (Session::get('admin_user.id') != 1) {
$this->checkAuth($request);
}
}
return $next($request);
}
protected function checkAuth($request)
{
$route = strtolower($request->controller().'/'.$request->action());
$allowNodes = Session::get('admin_user.nodes') ?: [];
if (!in_array($route, $allowNodes)) {
if ($request->isAjax()) {
return json(['code'=>403, 'msg'=>'无权限访问']);
} else {
abort(403, '无权限访问');
}
}
}
}
2. 权限树形结构生成
<?php
namespace appadminservice;
class NodeService
{
public static function getTree($nodes)
{
$tree = [];
foreach ($nodes as $node) {
if ($node['pid'] == 0) {
$tree[$node['id']] = $node;
} else {
$tree[$node['pid']]['children'][] = $node;
}
}
return array_values($tree);
}
public static function getFlattenNodes($nodes)
{
$result = [];
foreach ($nodes as $node) {
$result[] = strtolower($node['route']);
if (!empty($node['children'])) {
$result = array_merge($result, self::getFlattenNodes($node['children']));
}
}
return $result;
}
}
三、后台功能实现
1. 用户登录与权限初始化
<?php
namespace appadmincontroller;
use thinkfacadeSession;
use appadminserviceNodeService;
class Login
{
public function doLogin()
{
$username = input('post.username');
$password = input('post.password');
$user = AdminUser::where('username', $username)
->find();
if (!$user || !password_verify($password, $user['password'])) {
return json(['code'=>400, 'msg'=>'账号或密码错误']);
}
// 获取用户权限节点
$nodes = $this->getUserNodes($user['id']);
Session::set('admin_user', [
'id' => $user['id'],
'username' => $user['username'],
'nodes' => NodeService::getFlattenNodes($nodes)
]);
return json(['code'=>200, 'msg'=>'登录成功']);
}
protected function getUserNodes($userId)
{
$query = AdminNode::alias('n')
->join('admin_role_node rn', 'n.id = rn.node_id')
->join('admin_user_role ur', 'rn.role_id = ur.role_id')
->where('ur.user_id', $userId)
->where('n.status', 1)
->order('n.sort', 'desc')
->select();
return NodeService::getTree($query->toArray());
}
}
2. 动态菜单生成
<?php
namespace appadmincontroller;
class Index
{
public function menu()
{
$menu = Session::get('admin_user.menu_tree') ?: [];
return json([
'code' => 200,
'data' => $menu
]);
}
}
// 前端Vue组件示例
<template>
<el-menu router :default-active="$route.path">
<template v-for="item in menuData">
<el-submenu v-if="item.children" :index="item.route">
<template #title>
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</template>
<el-menu-item
v-for="child in item.children"
:key="child.route"
:index="child.route"
>
{{ child.name }}
</el-menu-item>
</el-submenu>
<el-menu-item v-else :index="item.route">
<i :class="item.icon"></i>
<span>{{ item.name }}</span>
</el-menu-item>
</template>
</el-menu>
</template>
四、高级功能扩展
1. 数据权限控制
<?php
namespace appadminservice;
class DataScopeService
{
public static function applyScope($query, $user)
{
// 获取用户数据权限范围
$scope = self::getUserDataScope($user['id']);
switch ($scope['type']) {
case 1: // 全部数据
break;
case 2: // 自定义部门
$query->whereIn('dept_id', $scope['dept_ids']);
break;
case 3: // 本部门
$query->where('dept_id', $user['dept_id']);
break;
case 4: // 本人
$query->where('user_id', $user['id']);
break;
}
return $query;
}
}
2. 操作日志记录
<?php
namespace appadminmiddleware;
class OperationLog
{
public function handle($request, Closure $next)
{
$response = $next($request);
if ($request->isPost() || $request->isPut() || $request->isDelete()) {
AdminLog::create([
'user_id' => Session::get('admin_user.id'),
'ip' => $request->ip(),
'method' => $request->method(),
'path' => $request->pathinfo(),
'params' => json_encode($request->param(), JSON_UNESCAPED_UNICODE),
'status' => $response->getCode(),
'create_time' => time()
]);
}
return $response;
}
}
五、性能优化方案
1. 权限缓存策略
<?php
namespace appadminservice;
use thinkfacadeCache;
class AuthCache
{
const CACHE_PREFIX = 'admin_auth:';
public static function getUserNodes($userId)
{
$cacheKey = self::CACHE_PREFIX . $userId;
if (Cache::has($cacheKey)) {
return Cache::get($cacheKey);
}
$nodes = self::fetchUserNodesFromDb($userId);
Cache::set($cacheKey, $nodes, 3600);
return $nodes;
}
public static function clearUserCache($userId)
{
Cache::delete(self::CACHE_PREFIX . $userId);
}
}
2. 权限验证优化
<?php
namespace appadminservice;
class FastAuthCheck
{
public static function check($route, $userId)
{
static $userNodes = [];
if (!isset($userNodes[$userId])) {
$userNodes[$userId] = AuthCache::getUserNodes($userId);
}
return in_array($route, $userNodes[$userId]);
}
}