本文目录导读:

在 PHP 中实现“授权注解”(Authorization Annotations)通常需要借助反射和自定义注解解析,因为 PHP 原生不支持注解(直到 PHP 8.0+ 才支持原生注解,但仍需手动处理逻辑)。
下面我给你一个完整可用的示例,演示如何通过注解实现简单的权限控制(@RequireRole)。
定义注解类(PHP 8.0+ 原生注解)
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class RequireRole
{
public array $roles;
public function __construct(string ...$roles)
{
$this->roles = $roles;
}
}
注意:
#[Attribute]标记这是一个注解类,TARGET_METHOD表示可作用于方法。
编写注解解析器(核心逻辑)
class AuthMiddleware
{
public static function check(object $controller, string $method): void
{
$reflection = new ReflectionMethod($controller, $method);
$attributes = $reflection->getAttributes(RequireRole::class);
if (empty($attributes)) {
// 没有权限限制,放行
return;
}
/** @var RequireRole $requireRole */
$requireRole = $attributes[0]->newInstance();
// 模拟获取当前用户角色(实际应从 session / token 获取)
$currentUserRole = $_SESSION['user_role'] ?? 'guest';
if (!in_array($currentUserRole, $requireRole->roles)) {
http_response_code(403);
echo "权限不足,需要角色: " . implode(', ', $requireRole->roles);
exit;
}
}
}
使用注解的业务控制器
class UserController
{
#[RequireRole('admin')]
public function deleteUser(int $userId): void
{
echo "用户 {$userId} 已被删除(管理员权限已验证)";
}
#[RequireRole('admin', 'editor')]
public function editUser(int $userId): void
{
echo "编辑用户 {$userId}(管理员/编辑权限已验证)";
}
public function viewUser(int $userId): void
{
echo "查看用户 {$userId}(无需特殊权限)";
}
}
路由/调用处统一进行权限校验
// 模拟路由分发 $route = $_GET['action'] ?? 'viewUser'; $userId = (int)($_GET['id'] ?? 1); $controller = new UserController(); // 执行权限检查(核心调用) AuthMiddleware::check($controller, $route); // 权限通过后,调用实际方法 $controller->$route($userId);
测试效果
- 当访问
?action=deleteUser&id=5且当前用户角色不是admin→ 显示 403 错误。 - 当访问
?action=editUser&id=3且角色是editor→ 正常执行。 - 当访问
?action=viewUser&id=1→ 直接放行(无注解)。
如果需要兼容 PHP 7.x(没有原生注解)
可以使用 Doctrine Annotations 库,或使用 PHPDoc 注释 手动解析:
/**
* @RequireRole("admin", "editor")
*/
public function editUser(int $userId): void
{
// ...
}
再通过 ReflectionMethod::getDocComment() 和正则提取注解内容。
总结核心流程
- 定义注解类(PHP 8.0+ 用
#[Attribute],旧版用注释标记) - 反射读取注解 → 获取权限要求
- 比较当前用户角色 → 通过则放行,否则拒绝
- 在路由/控制器调用前统一执行
check()
这样你就拥有了一套基于注解的授权系统,适合中小型框架或项目使用,如果需要更成熟的方案,可以看 Symfony Security 或 Laravel Policies + Gates。