在hyperf中需自定义权限校验注解:注解类须置于appnnotation下,用@annotation、@target、@retention声明,并在annotations.php中配置scan路径;切面继承abstractaspect,用annotationcollector获取注解,异步查权限并缓存结果。

Hyperf里怎么定义一个权限校验注解
Hyperf本身不带权限注解,得自己写。核心是用 @Annotation + @Target + @Retention 三件套声明注解类,且必须放在 AppAnnotation 下(或你配置的注解扫描路径),否则 AnnotationCollector 扫不到。
常见错误是把注解类放在 AppController 或随便一个目录下,结果切面里调用 AnnotationCollector::getAnnotationsByClass() 始终返回空数组。
- 注解类必须加
@Target({Target::CLASS, Target::METHOD}),不然无法标注在控制器方法上 - 注解属性建议只用简单类型(
string、int、bool、string[]),避免传对象或闭包——Hyperf注解解析器不支持序列化复杂结构 - 别忘了在
config/autoload/annotations.php的scan配置里加上你的注解命名空间,比如'App\Annotation\'
怎么用切面拦截带权限注解的方法
切面类要继承 AbstractAspect,并用 @Aspect 注解声明;关键在于 process 方法里拿到目标方法的注解,再结合当前用户做判断。别直接在 before 里 throw 异常——Hyperf 的 AOP 是基于协程的,异常需走 throw new RuntimeException(),否则可能被吞掉或导致协程静默退出。
示例逻辑:先从 $proceedingJoinPoint->className 和 $proceedingJoinPoint->methodName 构造类方法标识,再用 AnnotationCollector::getAnnotationsByMethod() 拿到注解实例,最后查用户角色/权限表或缓存。
- 不要在切面里调用阻塞式 DB 查询(如
Db::table()->where()->first()),应改用CoMySQL或Coroutine::create包裹异步操作 - 如果权限检查失败,推荐抛
AuthorizationException(自定义异常),并在全局异常处理器中统一返回 403,而不是直接return response()->json()—— 否则后续中间件和响应生命周期会被跳过 - 注意切面顺序:多个切面共存时,用
@Priority控制执行先后,权限切面通常要比日志、事务切面更早触发
为什么 AnnotationCollector::getAnnotationsByMethod() 总是空
最常见原因是注解没被正确加载——不是代码写错了,而是 Hyperf 的注解扫描机制依赖 Composer 的 autoloader 和 scan 配置双重生效。哪怕注解类语法完全正确,只要没出现在 config/autoload/annotations.php 的 scan.paths 列表里,运行时就等于不存在。
- 确认
composer dump-autoload -o已执行(尤其改过命名空间后) - 检查
scan配置是否漏了子目录,比如你放注解在AppAnnotationPermission,但配置只写了AppAnnotation,某些版本会扫不到 - 调试时可在切面里加一行
var_dump(AnnotationCollector::getAnnotationsByClass($proceedingJoinPoint->className)),看类级注解是否存在,排除是方法级标注问题还是整个扫描失效
权限校验结果要不要缓存,怎么缓存
每次请求都查数据库或 Redis 查权限关系,开销不小。建议对「用户-接口」组合做短时效缓存(比如 5 分钟),键名可用 perm:uid:{uid}:route:{controller}.{action}。注意别缓存用户身份本身(如 token 解析结果),那该由鉴权中间件负责。
- 缓存 key 必须包含用户 ID 和方法全限定名(
$className . '::' . $methodName),不能只缓存权限规则字符串——不同用户对同一接口权限可能不同 - 如果用了 Swoole Table 存用户 session,别把权限结果也往 Table 里塞,Table 不支持复杂结构序列化,容易出
unserialize() error - 更新权限配置后,要主动清除相关缓存,可以用事件监听(如监听
PermissionUpdated事件)或清 Redis 模糊 key(redis-cli --scan --pattern 'perm:uid:*')
权限注解看着轻量,但实际落地时最容易卡在注解扫描失效和切面异常捕获不完整这两点上,动手前先跑通一个最小可验证注解+切面组合,比堆功能更重要。











