Hyperf中自定义注解+Aspect实现权限校验的关键卡点是注解扫描、元数据获取和协程安全:注解类须置于AppAnnotation下并配置scan.paths,切面需用AnnotationCollector结合ProceedingJoinPoint安全取元数据,且DB查询须异步、异常须继承RuntimeException并在ExceptionHandler中统一处理。

Hyperf 里自定义注解 + Aspect 做权限校验,不是“写完就能用”,关键卡点在注解扫描、元数据获取和协程安全这三处。
注解类为什么 AnnotationCollector 找不到
最常见现象:AnnotationCollector::getAnnotationsByMethod() 返回空数组,但代码明明写了 @PreAuthorization。根本原因不是语法错,而是注解没被框架加载进来。
- 注解类必须放在
AppAnnotation下(或你显式配置的扫描路径),不能塞进AppController或随便建个目录 -
config/autoload/annotations.php的scan配置必须包含你的注解命名空间,比如'AppAnnotation\'—— 注意末尾双反斜杠 - 注解类必须带
@Target({Target::CLASS, Target::METHOD}),否则无法标注到控制器方法上 - 别用复杂类型当注解属性,
value只用string、int、bool或string[];传对象或闭包会导致解析失败
切面中怎么安全获取并校验注解
切面里不能靠反射硬查,得用 AnnotationCollector + $proceedingJoinPoint 构造上下文,否则在协程环境下容易拿错元数据。
- 用
$proceedingJoinPoint->className和$proceedingJoinPoint->methodName拼出完整方法标识,再调AnnotationCollector::getAnnotationsByMethod() - 不要在
process()里直接调Db::table()->first()这类同步 DB 查询,改用CoMySQL或Coroutine::create()包裹异步操作 - 权限检查失败时,抛
AuthorizationException(需自定义),别用return response()->json()—— 否则会跳过后续中间件和响应生命周期 - 多个切面共存时,用
@Priority(100)显式控制顺序,权限切面建议优先级高于日志、事务类切面
切面 process 方法里 throw 异常为啥不生效
现象:写了 throw new AuthorizationException(),但接口没返回 403,反而报 500 或静默失败。本质是协程异常处理机制和传统阻塞式不同。
- Hyperf AOP 的
process()是协程上下文,异常必须走throw new RuntimeException()或其子类,否则可能被协程调度器吞掉 - 全局异常处理器要能捕获
AuthorizationException,并在ExceptionHandler中明确返回response()->json(...)->withStatus(403) - 别在
before钩子里 throw —— Hyperf 只支持Around模式,before/after是伪概念,实际逻辑全在process()里写
真正难的不是写注解或切面,而是让它们在协程环境里稳定协作:注解得被扫进内存,元数据得在线程安全前提下取到,权限判断得异步完成且异常不丢失。每一步都绕不开 Hyperf 的 DI 容器初始化时机和注解扫描缓存机制。


















