ysy/hyperf-permission-annotation

Hyperf 3.1 权限注解

Installs: 7

Dependents: 0

Suggesters: 0

Security: 0

pkg:composer/ysy/hyperf-permission-annotation

1.0.0 2025-10-29 03:18 UTC

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_modelstringApp\Model\Admin必改!用户模型类(需继承 Hyperf\Database\Model\Model)App\Model\OaAdmin
user_attributestringoa_user必改!Token中间件传递用户信息的请求属性名(需和Token中间件一致)admin_user
user_role_fieldstringroles必改!用户表中存储角色ID的字段(格式:JSON数组,如 "[2,3]"role_ids
super_admin_fieldstringis_admin必改!用户表中超级管理员标识字段(值=1时为超级管理员,免普通权限验证)is_super
role_modelstringApp\Model\EnterpriseRole必改!角色模型类(需继承 Hyperf\Database\Model\Model)App\Model\OaRole
role_primary_keystringid角色表主键字段(默认id,支持自定义主键如 role_id)role_id
role_perm_fieldstringapi_unique必改!角色表中存储权限的字段(格式:JSON数组,如 "["todoList:select"]"permissions
role_status_fieldstringstatus角色表中状态字段(用于过滤“已禁用”的角色)is_enabled
role_status_enabledmixed1角色“启用状态”的值(需和角色表中“启用”的状态值一致)'Y'true

五、Permission注解参数详解

#[Permission()] 注解支持 3 个参数,覆盖所有权限控制场景,参数传递灵活,按需选择即可:

参数名类型默认值必要性用途说明
valuestring必传技术权限标识(需和角色表 role_perm_field 字段中的值一致,如 todoList:select
ignoreSuperAdminboolfalse可选是否忽略超级管理员免验证:
- false(默认):超级管理员直接放行;
- true:超级管理员也需验证当前权限
namestringnull可选权限中文名称(用户无权限时的提示文案,没传默认显示“该操作”)查看待办列表添加用户

注解参数使用示例(所有场景覆盖)

场景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.phpuser_modelrole_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:初始版本,支持注解参数、多角色权限合并、超级管理员控制、动态权限名称。