RBAC 权限模型
-- 用户表
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
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
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
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
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
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
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 模型 |
| 菜单 | 树形结构 |
| 日志 | 操作记录 |
| 字典 | 配置管理 |
后台系统的核心是权限管理,其他功能根据业务需求扩展。