本文目录导读:

在 PHP 中实现权限中间件(Authorization Middleware),核心思想是在请求进入具体业务逻辑之前进行拦截和校验,下面从基础原理到框架集成逐步介绍。
核心原理:前置拦截
权限中间件本质上是一个可调用的类或函数,它:
- 接收当前请求的上下文(路由、用户、角色等)
- 检查用户是否有权执行该操作
- 有权限则
next()继续,无权限则终止并返回错误
function middleware($request, $next) {
if (!checkPermission($request->user, $request->route)) {
return response('Forbidden', 403);
}
return $next($request);
}
原生 PHP 实现简单示例
不依赖框架,用最简方式演示:
// auth_middleware.php
function checkPermission($user, $requiredRole) {
// 假设用户角色存在 session 中
session_start();
$userRole = $_SESSION['role'] ?? 'guest';
$roles = [
'admin' => ['create', 'edit', 'delete'],
'editor' => ['create', 'edit'],
'viewer' => ['view']
];
return in_array($requiredRole, $roles[$userRole] ?? []);
}
// 在路由入口处使用
$route = $_GET['action'] ?? 'view';
if (!checkPermission($_SESSION['user'] ?? null, $route)) {
http_response_code(403);
echo json_encode(['error' => 'Forbidden']);
exit;
}
// 继续执行正常逻辑
主流框架中的实现方式
1 Laravel(最常用)
// 1. 创建中间件
php artisan make:middleware CheckPermission
// 2. 编写逻辑(app/Http/Middleware/CheckPermission.php)
class CheckPermission
{
public function handle($request, Closure $next, ...$permissions)
{
// 获取当前用户(假设已登录)
$user = $request->user();
foreach ($permissions as $permission) {
if (!$user->can($permission)) {
abort(403, '你没有执行此操作的权限');
}
}
return $next($request);
}
}
// 3. 注册到 Kernel(app/Http/Kernel.php)
protected $routeMiddleware = [
// ...其他中间件
'permission' => \App\Http\Middleware\CheckPermission::class,
];
// 4. 在路由中使用
Route::get('/admin/users', function () {
// ...
})->middleware('permission:manage-users');
// 或者用权限门面
Route::middleware(['auth', 'permission:edit-posts'])->group(function () {
Route::post('/posts/{id}', [PostController::class, 'update']);
});
2 ThinkPHP 6+
// 1. 创建中间件
php think make:middleware AuthPermission
// 2. 编写(app/middleware/AuthPermission.php)
class AuthPermission
{
public function handle($request, \Closure $next)
{
// 假设已有 Auth 类判断登录
$user = Auth::user();
$currentRoute = $request->path();
if (!$user || !$user->hasPermission($currentRoute)) {
return redirect('/403')->with('error', '无权限');
}
return $next($request);
}
}
// 3. 注册(config/middleware.php)
return [
'AuthPermission' => app\middleware\AuthPermission::class,
];
// 4. 在路由或控制器使用
Route::get('admin/users', 'Admin/UserController@index')->middleware('AuthPermission');
3 Symfony(通用模式)
// 使用 AccessDecisionManager
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class PermissionMiddleware
{
public function __construct(
private AuthorizationCheckerInterface $authChecker
) {}
public function onKernelController($event)
{
$request = $event->getRequest();
$attributes = $request->attributes;
// 从路由注解或 YAML 中获取所需权限
$requiredPermission = $attributes->get('_permission');
if ($requiredPermission && !$this->authChecker->isGranted($requiredPermission)) {
throw new AccessDeniedException('权限不足');
}
}
}
关键设计模式
角色-权限分离(RBAC 简化版)
class PermissionMiddleware
{
private array $rolePermissions = [
'admin' => ['*'], // 全部权限
'manager' => ['view_report', 'edit_report'],
'staff' => ['view_report'],
];
public function handle($user, string $requiredPermission): bool
{
$role = $user->role ?? 'guest';
$permissions = $this->rolePermissions[$role] ?? [];
// 超级管理员有 * 通配符
if (in_array('*', $permissions)) return true;
return in_array($requiredPermission, $permissions);
}
}
注解式权限(PHP 8 Attributes)
#[Attribute(Attribute::TARGET_METHOD)]
class RequirePermission {
public function __construct(public string $permission) {}
}
class PostController {
#[RequirePermission('delete_posts')]
public function delete(int $id) {
// ...
}
}
// 中间件中解析注解
$reflection = new ReflectionMethod($controller, $method);
$attributes = $reflection->getAttributes(RequirePermission::class);
if (!empty($attributes)) {
$permission = $attributes[0]->newInstance()->permission;
// 检查权限
}
最佳实践建议
| 原则 | 说明 |
|---|---|
| 职责单一 | 中间件只负责检查权限,具体分配逻辑交给其他系统 |
| 尽早返回 | 无权限立即 403,不要浪费后续资源 |
| 缓存角色权限 | 避免每次请求都查数据库(可用 Redis / 本地存储) |
| 支持多种策略 | 如:白名单(只允许某些IP)、黑名单、动态权限(如资源所有者) |
| 清晰错误提示 | 区分“未登录”(401)和“无权限”(403) |
| 调试友好 | 开发环境可记录谁在什么时间请求了什么被拒绝 |
示例:一个可复用的通用权限中间件(不依赖框架)
interface PermissionChecker {
public function hasPermission(string $user, string $permission): bool;
}
class SimpleRoleChecker implements PermissionChecker {
private array $roles;
public function __construct(array $roles) {
$this->roles = $roles;
}
public function hasPermission(string $userRole, string $permission): bool {
$perms = $this->roles[$userRole] ?? [];
return in_array($permission, $perms) || in_array('*', $perms);
}
}
class PermissionMiddleware {
private PermissionChecker $checker;
public function __construct(PermissionChecker $checker) {
$this->checker = $checker;
}
public function handle(callable $next, string $permission): mixed {
$userRole = $_SESSION['role'] ?? 'guest';
if (!$this->checker->hasPermission($userRole, $permission)) {
http_response_code(403);
return ['error' => 'Forbidden'];
}
return $next();
}
}
// 使用
$roles = [
'admin' => ['*'],
'editor' => ['create_post', 'edit_post'],
];
$middleware = new PermissionMiddleware(new SimpleRoleChecker($roles));
$result = $middleware->handle(function() {
return "正常响应内容";
}, 'create_post');
- 核心:在请求处理前拦截,检查用户身份与权限
- 框架:Laravel/ThinkPHP/Symfony 都提供完善的中间件机制
- 进阶:结合 RBAC、ABAC 模型、注解/属性、策略模式
- 效率:权限查找尽量使用缓存,减少数据库开销
如果你能提供更具体的场景(如使用哪个框架、权限模型是 RBAC 还是资源级),我可以给出更针对性的代码示例。