ysy / hyperf-permission-annotation
Hyperf 3.1 权限注解
Requires
- php: >=8.2
This package is not auto-updated.
Last update: 2025-11-12 06:41:03 UTC
README
Hyperf 3.1 专属权限验证包,基于 PHP 8 Attribute 注解实现,支持动态权限名称、多角色权限合并、超级管理员灵活控制,零侵入业务代码,接口加注解即可生效。
一、环境要求
- PHP ≥ 8.2(需支持 Attribute 注解)
- Hyperf ≥ 3.1(适配 Hyperf 3.1 中间件、依赖注入规范)
- 已配置数据库连接(需访问「用户表」和「角色表」)
- 已实现 Token 验证中间件(需传递用户信息到请求属性)
二、安装步骤
1. 安装包
通过 Composer 安装,项目根目录执行命令:
composer require ysy/hyperf-permission-annotation:1.0.0
2. 发布配置文件
安装后需发布权限包配置模板(路径:config/autoload/permission.php),执行命令:
php bin/hyperf.php vendor:publish ysy/hyperf-permission-annotation
发布成功后,会在 config/autoload 目录下生成 permission.php 配置文件,后续只需修改该文件适配你的项目。
三、快速使用(3步上手)
以「查看待办列表接口」为例,演示完整使用流程:
步骤1:修改配置文件(适配你的项目表结构)
打开 config/autoload/permission.php,根据你的数据库表结构修改配置(所有配置项都有说明,必改项已标红):
配置项中数据如有略微的对不上,可在数据获取后略微调整,以适配配置文件
<?php
return [
// -------------------------- 必改:用户相关配置 --------------------------
'user_model' => 'App\Model\Admin', // 你的用户模型类(如:App\Model\OaAdmin)
'user_attribute' => 'oa_user', // Token中间件传递的用户属性名(需和Token中间件一致)
'user_role_field' => 'roles', // 用户表中「存储角色ID」的字段(格式:JSON数组,如 ["2", "3"]),用户表中有个roles字段
'super_admin_field' => 'is_admin', // 用户表中「超级管理员标识」字段(值=1时为超级管理员),用户表中有这个字段
// -------------------------- 必改:角色相关配置 --------------------------
'role_model' => 'App\Model\EnterpriseRole', // 你的角色模型类(如:App\Model\OaRole)
'role_primary_key' => 'id', // 角色表主键字段(默认id,支持自定义如 role_id)
'role_perm_field' => 'api_unique', // 角色表中「存储权限」的字段(格式:JSON数组,如 ["todoList:select"])
'role_status_field' => 'status', // 角色表中「状态」字段(如 is_enabled)
'role_status_enabled' => 1, // 角色「启用状态」的值(默认1,支持自定义如 'Y')
];
步骤2:确保Token中间件正确传递用户信息
你的 Token 中间件(如 JWT 中间件)需在验证通过后,将「用户模型实例」存入 $request->getAttribute('user_attribute配置的值')(默认是 oa_user)。
Token 中间件示例(简化版):
<?php
namespace App\Middleware;
use App\Model\Admin; // 和你配置的 user_model 一致
use Hyperf\HttpServer\Contract\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class JwtMiddleware implements MiddlewareInterface
{
public function __construct(protected RequestInterface $request) {}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// 1. 解析Token获取用户ID(你的Token解析逻辑)
$token = $request->getHeaderLine('Authorization');
$userId = $this->parseToken($token); // 你的Token解析方法
// 2. 查询用户模型(需和配置的 user_model 一致)
$user = Admin::query()->find($userId);
// 3. 传递用户信息到请求属性(键名需和 user_attribute 配置一致)
return $handler->handle($request->withAttribute('oa_user', $user));
}
}
步骤3:控制器加注解实现权限验证
在需要权限验证的接口方法上添加 #[Permission()] 注解,即可完成权限控制:
<?php
namespace App\Controller;
use App\Middleware\JwtMiddleware; // 你的Token中间件
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Ysy\Hyperf\PermissionAnnotation\Annotation\Permission; // 引入权限注解
use Ysy\Hyperf\PermissionAnnotation\Middleware\PermissionMiddleware;
#[Controller(prefix: '/api/todo')]
#[Middleware(JwtMiddleware::class)] // 先执行Token验证
class TodoController
{
/**
* 查看待办列表(需 todoList:select 权限)
* 注解说明:传技术权限标识 + 中文名称,用户无权限时会提示“无「查看待办列表」权限”
*/
#[GetMapping('list')]
#[Middleware(PermissionMiddleware::class)]
#[Permission(value: 'todoList:select', name: '查看待办列表')]
public function list()
{
// 你的业务逻辑(仅拥有 todoList:select 权限的用户能执行)
return [
'code' => 200,
'msg' => 'success',
'data' => ['待办1', '待办2']
];
}
}
四、详细配置说明
config/autoload/permission.php 所有配置项详解,按「用户相关」和「角色相关」分类,方便对应你的表结构:
| 配置项 | 类型 | 默认值 | 用途说明 | 示例值 |
|---|---|---|---|---|
| user_model | string | App\Model\Admin | 必改!用户模型类(需继承 Hyperf\Database\Model\Model) | App\Model\OaAdmin |
| user_attribute | string | oa_user | 必改!Token中间件传递用户信息的请求属性名(需和Token中间件一致) | admin_user |
| user_role_field | string | roles | 必改!用户表中存储角色ID的字段(格式:JSON数组,如 "[2,3]") | role_ids |
| super_admin_field | string | is_admin | 必改!用户表中超级管理员标识字段(值=1时为超级管理员,免普通权限验证) | is_super |
| role_model | string | App\Model\EnterpriseRole | 必改!角色模型类(需继承 Hyperf\Database\Model\Model) | App\Model\OaRole |
| role_primary_key | string | id | 角色表主键字段(默认id,支持自定义主键如 role_id) | role_id |
| role_perm_field | string | api_unique | 必改!角色表中存储权限的字段(格式:JSON数组,如 "["todoList:select"]") | permissions |
| role_status_field | string | status | 角色表中状态字段(用于过滤“已禁用”的角色) | is_enabled |
| role_status_enabled | mixed | 1 | 角色“启用状态”的值(需和角色表中“启用”的状态值一致) | 'Y'、true |
五、Permission注解参数详解
#[Permission()] 注解支持 3 个参数,覆盖所有权限控制场景,参数传递灵活,按需选择即可:
| 参数名 | 类型 | 默认值 | 必要性 | 用途说明 | |
|---|---|---|---|---|---|
| value | string | 无 | 必传 | 技术权限标识(需和角色表 role_perm_field 字段中的值一致,如 todoList:select) | |
| ignoreSuperAdmin | bool | false | 可选 | 是否忽略超级管理员免验证: - false(默认):超级管理员直接放行;- true:超级管理员也需验证当前权限 | |
| name | string | null | 可选 | 权限中文名称(用户无权限时的提示文案,没传默认显示“该操作”) | 查看待办列表、添加用户 |
注解参数使用示例(所有场景覆盖)
场景1:基础用法(仅传必选参数value)
没传 name 时,用户无权限会提示“无「该操作」权限”,适合不需要具体名称的场景:
#[Post('add')]
#[Permission(value: 'user:add')] // 仅传技术权限标识
public function add()
{
// 业务逻辑...
}
// 无权限返回:{"code":403,"msg":"无「该操作」权限","data":{"required":"user:add","owned":["user:list"]}}
场景2:传value+name(显示具体中文提示)
传 name 后,用户无权限会显示具体名称(如“无「添加用户」权限”),用户体验更好:
#[Post('add')]
#[Permission(value: 'user:add', name: '添加用户')] // 技术标识+中文名称
public function add()
{
// 业务逻辑...
}
// 无权限返回:{"code":403,"msg":"无「添加用户」权限","data":{"required":"user:add","owned":["user:list"]}}
场景3:传value+ignoreSuperAdmin(强制验证超级管理员)
默认超级管理员免验证,传 ignoreSuperAdmin: true 后,即使是超级管理员也需验证当前权限:
#[Delete('delete')]
#[Permission(value: 'order:delete', ignoreSuperAdmin: true, name: '删除订单')]
public function delete()
{
// 业务逻辑(超级管理员也需 order:delete 权限才能执行)
}
六、中间件挂载方式
权限中间件(Ysy\Hyperf\PermissionAnnotation\Middleware\PermissionMiddleware)支持「控制器挂载」和「全局挂载」两种方式,按需选择:
方式1:控制器挂载(推荐)
在需要权限验证的控制器上通过 #[Middleware] 注解挂载,仅该控制器的接口生效:
<?php
namespace App\Controller;
use App\Middleware\JwtMiddleware;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\Middleware;
use Ysy\Hyperf\PermissionAnnotation\Middleware\PermissionMiddleware;
#[Controller(prefix: '/api/user')]
#[Middleware(JwtMiddleware::class)] // 先执行Token验证
#[Middleware(PermissionMiddleware::class)] // 再执行权限验证
class UserController
{
// 该控制器下所有加了 #[Permission] 注解的接口都会验证权限
#[Post('add')]
#[Permission(value: 'user:add', name: '添加用户')]
public function add() {}
}
方式2:全局挂载(所有接口生效)
在 config/autoload/middlewares.php 中配置全局HTTP中间件,所有接口都会执行权限验证(无 #[Permission] 注解的接口会自动放行):
<?php
// config/autoload/middlewares.php
return [
'http' => [
App\Middleware\JwtMiddleware::class, // Token中间件(先执行)
Ysy\Hyperf\PermissionAnnotation\Middleware\PermissionMiddleware::class, // 权限中间件(后执行)
],
];
七、权限验证返回示例
不同场景下的权限验证返回结果,方便前端处理提示:
1. 无权限(传了name参数)
{
"code": 403,
"msg": "无「查看待办列表」权限",
"data": {
"required": "todoList:select", // 所需技术权限标识(前端调试用)
"owned": ["user:list", "user:add"] // 用户已拥有的权限(前端调试用)
}
}
2. 无权限(没传name参数,默认提示)
{
"code": 403,
"msg": "无「该操作」权限",
"data": {
"required": "user:add",
"owned": ["user:list"]
}
}
3. 用户未分配角色
{
"code": 403,
"msg": "用户未分配有效角色",
"data": []
}
4. 角色无任何权限
{
"code": 403,
"msg": "用户角色无任何权限",
"data": []
}
八、常见问题排查
1. 注解不生效,接口直接放行?
- 检查是否挂载了权限中间件(
PermissionMiddleware),需在 Token 中间件之后执行; - 检查接口方法是否添加了
#[Permission()]注解,且value参数是否正确; - 检查
config/autoload/permission.php中user_model和role_model是否正确(需是完整类名)。
2. 报错“未获取到有效用户(需先执行Token中间件)”?
- 检查 Token 中间件是否正确将用户模型存入
$request->getAttribute('user_attribute配置的值'); - 检查
user_attribute配置是否和 Token 中间件传递的属性名一致(如配置是oa_user,Token中间件也需传oa_user)。
3. 报错“权限配置未找到,请执行vendor:publish命令”?
- 未执行
php bin/hyperf.php vendor:publish ysy/hyperf-permission-annotation命令,需先发布配置文件。
4. 多角色权限未合并?
- 检查用户表
user_role_field字段是否是 JSON 数组格式(如"[2,3]",非[2,3]或"2,3"); - 权限包会自动合并用户所有“启用角色”的权限,无需额外配置。
九、版本信息
- 1.0.0:初始版本,支持注解参数、多角色权限合并、超级管理员控制、动态权限名称。