ysy / hyperf-permission-annotation
Hyperf 3.1 权限注解
1.0.0
2025-10-28 07:42 UTC
Requires
- php: >=8.2
This package is not auto-updated.
Last update: 2025-10-28 20:27:03 UTC
README
适配 Hyperf 3.1 的轻量级权限验证包,基于 PHP 8 Attribute 注解实现,支持灵活配置表结构、自定义角色/用户模型,无需侵入业务代码,接口加注解即可生效。
一、包特性
- 简洁易用:基于 PHP 8 Attribute 注解,
#[Permission('user:list')]一句话实现权限验证; - 高度灵活:支持自定义角色主键(如
role_id)、角色启用状态值(如Y/1)、用户/角色模型; - 性能友好:一次联表查询获取权限,避免重复数据库操作;
- 兼容 Hyperf 3.1:对齐 Hyperf 3.1 中间件、注解扫描、依赖注入规范;
- 超级管理员免验证:默认支持超级管理员(可配置字段)直接放行,也可强制验证。
二、安装步骤
1. 环境要求
- PHP ≥ 8.0
- Hyperf ≥ 3.1
- 已配置数据库连接(需访问用户表、角色表)
2. 安装包
方式1:从 Packagist 安装(推荐,线上环境)
composer require ysy/hyperf-permission-annotation:^1.0
方式2:本地开发(本地包测试)
- 将包代码放在项目同级目录(如
../hyperf31-permission); - 在项目
composer.json中添加本地包路径:"repositories": [ { "type": "path", "url": "../hyperf31-permission" } ] - 执行安装:
composer require ysy/hyperf-permission-annotation:dev-main --prefer-source
3. 发布配置文件
安装后执行以下命令,生成权限包配置文件(路径:config/autoload/permission.php):
php bin/hyperf.php vendor:publish ysy/hyperf-permission-annotation
三、配置说明
打开 config/autoload/permission.php,根据项目实际表结构修改配置,所有参数均有默认值,非特殊场景无需全改:
| 配置项 | 类型 | 默认值 | 用途说明 |
|---|---|---|---|
user_model | string | App\Model\Admin | 用户模型类(需继承 Hyperf Model) |
user_attribute | string | oa_user | Token 中间件传递的用户信息属性名(如 $request->getAttribute('oa_user')) |
user_role_field | string | roles | 用户表中存储角色的字段(格式:JSON 数组,如 ["2"]) |
super_admin_field | string | is_admin | 超级管理员标识字段(值为 1 时免验证,可自定义) |
role_model | string | App\Model\EnterpriseRole | 角色模型类(需继承 Hyperf Model) |
role_primary_key | string | id | 角色表主键字段(支持非 id,如 role_id) |
role_perm_field | string | api_unique | 角色表中存储权限的字段(格式:JSON 数组,如 ["user:list"]) |
role_status_field | string | status | 角色状态字段(如 is_enabled) |
role_status_enabled | mixed | 1 | 角色启用状态值(支持 1/Y/true,如 'Y') |
配置示例(非默认场景)
若项目中角色表用 role_id 做主键,状态字段 is_enabled 取值 Y/N,配置修改如下:
return [
// 用户相关(假设用户模型是 App\Model\OaAdmin)
'user_model' => 'App\Model\OaAdmin',
'user_attribute' => 'oa_user', // Token 中间件传递的用户属性名
// 角色相关(自定义主键和状态值)
'role_model' => 'App\Model\OaRole',
'role_primary_key' => 'role_id', // 角色表主键:role_id
'role_status_field' => 'is_enabled', // 角色状态字段:is_enabled
'role_status_enabled' => 'Y', // 启用状态值:Y
'role_perm_field' => 'perm_keys', // 角色权限字段:perm_keys
];
四、使用示例
前置条件:Token 中间件
权限包依赖 Token 中间件传递用户信息,需确保:
- 项目已实现 Token 验证中间件(如 JWT、OAuth2);
- Token 验证通过后,将用户模型实例存入
$request->getAttribute($config['user_attribute'])(默认是oa_user)。
Token 中间件示例(简化版):
// App\Middleware\OaTokenMiddleware.php
class OaTokenMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// 1. 解析 Token 获取用户 ID
$token = $request->getHeaderLine('Authorization');
$userId = $this->parseTokenGetUserId($token);
// 2. 查询用户模型
$user = OaAdmin::query()->find($userId);
// 3. 传递用户信息到请求属性
return $handler->handle($request->withAttribute('oa_user', $user));
}
}
场景1:基础权限验证(最常用)
给接口添加 #[Permission('权限标识')] 注解,自动验证用户是否拥有该权限。
控制器代码
<?php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use YourName\Hyperf31Permission\Annotation\Permission;
use App\Middleware\OaTokenMiddleware; // 你的 Token 中间件
#[Controller(prefix: '/api/user')]
#[Middleware(OaTokenMiddleware::class)] // 先执行 Token 验证
class UserController
{
/**
* 示例:获取用户列表(需 user:list 权限)
* 注解说明:#[Permission('权限标识')]
*/
#[GetMapping('list')]
#[Permission('user:list')] // 核心:添加权限注解
public function list()
{
// 业务逻辑:查询用户列表
$users = [['id' => 1, 'name' => '张三'], ['id' => 2, 'name' => '李四']];
return $this->success([
'code' => 200,
'data' => $users,
'msg' => '获取成功'
]);
}
}
场景2:忽略超级管理员(强制验证)
默认超级管理员(super_admin_field 字段值为 1)会免验证,若需强制超级管理员也验证权限,添加 ignoreSuperAdmin: true 参数。
控制器代码
#[Controller(prefix: '/api/order')]
#[Middleware(OaTokenMiddleware::class)]
class OrderController
{
/**
* 示例:创建订单(需 order:create 权限,超级管理员也需验证)
* 注解说明:#[Permission('权限标识', ignoreSuperAdmin: true)]
*/
#[Post('create')]
#[Permission('order:create', ignoreSuperAdmin: true)] // 强制验证超级管理员
public function create()
{
// 业务逻辑:创建订单
return $this->success([
'code' => 200,
'msg' => '订单创建成功'
]);
}
}
场景3:多角色适配(用户含多个角色)
用户表 roles 字段存储多角色(如 ["2", "3"]),包会自动合并所有角色的权限,只要任一角色有目标权限即可通过。
配置无需修改(默认支持多角色)
// 用户表 roles 字段值(JSON 数组)
$user->roles = '["2", "3"]'; // 角色 2 和角色 3
// 角色表权限(自动合并)
// 角色 2 的 api_unique:["user:list"]
// 角色 3 的 api_unique:["user:add"]
// 最终用户拥有的权限:["user:list", "user:add"]
控制器代码
#[GetMapping('add')]
#[Permission('user:add')] // 只要任一角色有 user:add 权限即可通过
public function add()
{
return $this->success(['code' => 200, 'msg' => '用户添加成功']);
}
场景4:自定义角色表结构(非默认主键/状态)
若角色表用 role_id 做主键,状态字段 is_enabled 取值 Y/N(对应配置见「配置示例」),无需修改控制器代码,仅需确保配置正确。
角色表数据示例
| role_id | role_name | is_enabled | perm_keys(权限字段) |
|---|---|---|---|
| 2 | 普通管理员 | Y | ["user:list", "user:add"] |
| 3 | 只读用户 | Y | ["user:list"] |
控制器代码(和场景1一致,无需改)
#[GetMapping('list')]
#[Permission('user:list')] // 自动用 role_id 查角色,is_enabled=Y 过滤启用角色
public function list()
{
// 业务逻辑...
}
五、注解参数详解
#[Permission()] 注解支持 2 个参数,所有参数均有默认值,按需传递即可:
| 参数名 | 类型 | 默认值 | 用途说明 |
|---|---|---|---|
value | string | 无 | 必传!目标权限标识(需和角色表 role_perm_field 字段中的值一致,如 user:list) |
ignoreSuperAdmin | bool | false | 可选!是否忽略超级管理员免验证: - false(默认):超级管理员直接放行;- true:超级管理员也需验证权限 |
注解使用示例(所有参数组合)
// 1. 仅传必选参数(超级管理员免验证)
#[Permission('user:list')]
// 2. 传必选参数 + 可选参数(强制验证超级管理员)
#[Permission('order:create', ignoreSuperAdmin: true)]
六、常见问题排查
1. 注解不生效,接口直接放行?
- 检查是否执行了 Token 中间件(权限包依赖用户信息);
- 检查
config/autoload/annotations.php中是否包含包的注解目录(Hyperf 3.1 会自动注册,无需手动加); - 检查控制器方法是否正确添加
#[Permission()]注解,且权限标识拼写正确。
2. 报错“未获取到有效用户”?
- 检查 Token 中间件是否将用户模型存入
$request->getAttribute($config['user_attribute'])(默认是oa_user); - 检查
config/autoload/permission.php中user_model配置是否和实际用户模型一致(如App\Model\OaAdmin)。
3. 报错“角色不存在或未启用”?
- 检查用户表
roles字段是否为 JSON 数组格式(如["2"],非[2]或"2"); - 检查
config/autoload/permission.php中role_primary_key、role_status_field、role_status_enabled是否和角色表结构一致(如主键是role_id而非id); - 检查角色表中目标角色是否存在,且状态值等于
role_status_enabled(如is_enabled=Y)。
4. 报错“无权限访问”?
- 检查角色表
role_perm_field字段(如api_unique)是否包含目标权限标识(如user:list); - 检查权限标识大小写是否一致(如
User:List和user:list是两个不同的权限)。
七、扩展建议
- 自定义异常响应:若需修改权限不足时的返回格式(如统一封装
code/msg/data),可在中间件中修改$this->response->json()的返回结构; - 多权限验证:若需支持“满足任一权限”或“满足所有权限”,可修改注解
value为数组(如#[Permission(['user:add', 'user:edit'])]),并在中间件中调整权限判断逻辑; - 缓存权限:若用户权限不频繁变更,可在中间件中添加 Redis 缓存(缓存用户的权限列表,过期时间按需设置),减少数据库查询。
八、版本更新日志
- v1.0.0:初始版本,支持基础权限验证、灵活配置、超级管理员免验证;
- v1.0.1:修复多角色权限合并去重问题,优化异常提示信息。