后台管理系统实战

RBAC 权限模型

sql 复制代码
-- 用户表  
CREATE TABLE admins (  
    id INT PRIMARY KEY AUTO_INCREMENT,  
    username VARCHAR(50) UNIQUE,  
    password VARCHAR(255),  
    nickname VARCHAR(50),  
    status TINYINT DEFAULT 1,  
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP  
);  
  
-- 角色表  
CREATE TABLE roles (  
    id INT PRIMARY KEY AUTO_INCREMENT,  
    name VARCHAR(50),  
    code VARCHAR(50) UNIQUE,  
    description VARCHAR(255)  
);  
  
-- 用户角色关联  
CREATE TABLE admin_roles (  
    admin_id INT,  
    role_id INT,  
    PRIMARY KEY (admin_id, role_id)  
);  
  
-- 菜单/权限表  
CREATE TABLE permissions (  
    id INT PRIMARY KEY AUTO_INCREMENT,  
    parent_id INT DEFAULT 0,  
    name VARCHAR(50),  
    code VARCHAR(100),  
    type TINYINT,  -- 1菜单 2按钮  
    path VARCHAR(200),  
    icon VARCHAR(50),  
    sort INT DEFAULT 0  
);  
  
-- 角色权限关联  
CREATE TABLE role_permissions (  
    role_id INT,  
    permission_id INT,  
    PRIMARY KEY (role_id, permission_id)  
);

权限验证

php 复制代码
<?php  
class PermissionService  
{  
    // 获取用户所有权限  
    public function getUserPermissions(int $adminId): array  
    {  
        $cacheKey = "admin:permissions:{$adminId}";  
          
        return Cache::remember($cacheKey, 3600, function () use ($adminId) {  
            return DB::table('admin_roles as ar')  
                ->join('role_permissions as rp', 'ar.role_id', '=', 'rp.role_id')  
                ->join('permissions as p', 'rp.permission_id', '=', 'p.id')  
                ->where('ar.admin_id', $adminId)  
                ->pluck('p.code')  
                ->unique()  
                ->toArray();  
        });  
    }  
      
    // 检查权限  
    public function hasPermission(int $adminId, string $code): bool  
    {  
        $permissions = $this->getUserPermissions($adminId);  
        return in_array($code, $permissions);  
    }  
      
    // 获取用户菜单  
    public function getUserMenus(int $adminId): array  
    {  
        $permissions = DB::table('admin_roles as ar')  
            ->join('role_permissions as rp', 'ar.role_id', '=', 'rp.role_id')  
            ->join('permissions as p', 'rp.permission_id', '=', 'p.id')  
            ->where('ar.admin_id', $adminId)  
            ->where('p.type', 1)  
            ->orderBy('p.sort')  
            ->get();  
          
        return $this->buildTree($permissions);  
    }  
      
    private function buildTree($items, $parentId = 0): array  
    {  
        $tree = [];  
        foreach ($items as $item) {  
            if ($item->parent_id == $parentId) {  
                $children = $this->buildTree($items, $item->id);  
                $node = (array) $item;  
                if ($children) {  
                    $node['children'] = $children;  
                }  
                $tree[] = $node;  
            }  
        }  
        return $tree;  
    }  
}

权限中间件

php 复制代码
<?php  
class CheckPermission  
{  
    public function handle(Request $request, Closure $next, string $permission)  
    {  
        $admin = auth('admin')->user();  
          
        if (!$this->permissionService->hasPermission($admin->id, $permission)) {  
            return response()->json(['error' => '无权限'], 403);  
        }  
          
        return $next($request);  
    }  
}  
  
// 路由使用  
Route::get('/users', [UserController::class, 'index'])  
    ->middleware('permission:user.list');  
Route::post('/users', [UserController::class, 'store'])  
    ->middleware('permission:user.create');

操作日志

php 复制代码
<?php  
class OperationLog  
{  
    public static function record(string $module, string $action, $data = null): void  
    {  
        DB::table('operation_logs')->insert([  
            'admin_id' => auth('admin')->id(),  
            'module' => $module,  
            'action' => $action,  
            'data' => json_encode($data),  
            'ip' => request()->ip(),  
            'user_agent' => request()->userAgent(),  
            'created_at' => now()  
        ]);  
    }  
}  
  
// 使用  
OperationLog::record('用户管理', '创建用户', ['username' => $user->username]);

数据字典

php 复制代码
<?php  
class DictService  
{  
    public function getByType(string $type): array  
    {  
        return Cache::remember("dict:{$type}", 3600, function () use ($type) {  
            return DB::table('dicts')  
                ->where('type', $type)  
                ->where('status', 1)  
                ->orderBy('sort')  
                ->get()  
                ->toArray();  
        });  
    }  
      
    public function getValue(string $type, $key): ?string  
    {  
        $items = $this->getByType($type);  
        foreach ($items as $item) {  
            if ($item->key == $key) {  
                return $item->value;  
            }  
        }  
        return null;  
    }  
}  
  
// 使用  
$statusText = $dictService->getValue('order_status', $order->status);

通用 CRUD

php 复制代码
<?php  
abstract class BaseController  
{  
    protected string $model;  
    protected array $searchFields = [];  
      
    public function index(Request $request)  
    {  
        $query = $this->model::query();  
          
        // 搜索  
        foreach ($this->searchFields as $field) {  
            if ($request->filled($field)) {  
                $query->where($field, 'like', "%{$request->input($field)}%");  
            }  
        }  
          
        // 排序  
        $query->orderBy($request->input('sort_field', 'id'), $request->input('sort_order', 'desc'));  
          
        // 分页  
        return $query->paginate($request->input('page_size', 15));  
    }  
      
    public function store(Request $request)  
    {  
        $data = $request->validated();  
        return $this->model::create($data);  
    }  
      
    public function update(Request $request, int $id)  
    {  
        $model = $this->model::findOrFail($id);  
        $model->update($request->validated());  
        return $model;  
    }  
      
    public function destroy(int $id)  
    {  
        $this->model::findOrFail($id)->delete();  
        return response()->json(['message' => '删除成功']);  
    }  
}

导出 Excel

php 复制代码
<?php  
use PhpOffice\PhpSpreadsheet\Spreadsheet;  
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;  
  
class ExportService  
{  
    public function export(array $headers, array $data, string $filename): string  
    {  
        $spreadsheet = new Spreadsheet();  
        $sheet = $spreadsheet->getActiveSheet();  
          
        // 写入表头  
        $col = 'A';  
        foreach ($headers as $header) {  
            $sheet->setCellValue($col . '1', $header);  
            $col++;  
        }  
          
        // 写入数据  
        $row = 2;  
        foreach ($data as $item) {  
            $col = 'A';  
            foreach ($item as $value) {  
                $sheet->setCellValue($col . $row, $value);  
                $col++;  
            }  
            $row++;  
        }  
          
        $path = storage_path("exports/{$filename}.xlsx");  
        $writer = new Xlsx($spreadsheet);  
        $writer->save($path);  
          
        return $path;  
    }  
}

总结

模块 关键点
权限 RBAC 模型
菜单 树形结构
日志 操作记录
字典 配置管理

后台系统的核心是权限管理,其他功能根据业务需求扩展。

相关推荐
大鸡腿同学6 小时前
【成长类】《只有偏执狂才能生存》读书笔记:程序员的偏执型成长地图
后端
0xDevNull6 小时前
MySQL数据冷热分离详解
后端·mysql
AI袋鼠帝6 小时前
OpenClaw(龙虾)最强开源对手!Github 40K Star了,又一个爆火的Agent..
后端
新知图书7 小时前
搭建Spring Boot开发环境
java·spring boot·后端
宸津-代码粉碎机8 小时前
Spring Boot 4.0虚拟线程实战调优技巧,最大化发挥并发优势
java·人工智能·spring boot·后端·python
小码哥_常8 小时前
一个Starter搞定六种防护,Spring Boot API的超强护盾来了
后端
小村儿10 小时前
连载04-最重要的Skill---一起吃透 Claude Code,告别 AI coding 迷茫
前端·后端·ai编程
IT_陈寒11 小时前
Vite的alias配置把我整不会了,原来是这个坑
前端·人工智能·后端
gelald11 小时前
Spring Boot - 自动配置原理
java·spring boot·后端
希望永不加班11 小时前
SpringBoot 集成测试:@SpringBootTest 与 MockMvc
java·spring boot·后端·log4j·集成测试