后台管理系统实战

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 模型
菜单 树形结构
日志 操作记录
字典 配置管理

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

相关推荐
Java编程爱好者2 小时前
字节Trae IDE全模式深度解析+Java后端实战技巧,架构师面试效率拉满
后端
Java水解2 小时前
你真的会打印日志吗?基于 Spring Boot 的全方位日志指南
spring boot·后端
Java水解2 小时前
Spring Boot 实战:MyBatis 操作数据库(上)
spring boot·后端
Java编程爱好者2 小时前
从 Spring Boot 到 Tomcat:很多人其实分不清“框架”和“服务器”
后端
Apifox2 小时前
Apifox 2 月更新|MCP Client 调试体验优化、测试套件持续升级、支持公用测试数据、测试报告优化
前端·后端·测试
神奇小汤圆3 小时前
SpringBoot实现微信登录,SoEasy!
后端
逍遥德3 小时前
Maven教程.02-基础-pom.xml 使用标签大全
java·后端·maven·软件构建
神奇小汤圆3 小时前
为什么Java里面,Service层不直接返回Result对象?
后端
Charlie_lll3 小时前
Redis脑裂问题处理——基于min-replicas-to-write配置
redis·后端