webman权限中间件必须重写prehandle()而非handle(),因prehandle()返回false可彻底中断请求链,而handle()的提前return无法阻止后续逻辑执行;需在prehandle()中解析token或session获取用户并注入request,结合路由option('permission')做声明式校验,拦截时按accept头动态返回json或重定向,并确保权限缓存及时失效。

Webman 的权限验证中间件必须用 preHandle() 拦截,不能靠返回值跳过后续逻辑;否则请求会继续穿透到控制器,权限控制形同虚设。
为什么 Webman 中间件必须重写 preHandle() 而非 handle()
Webman 的拦截器机制和 Laravel/ThinkPHP 不同:handle() 是“包裹式”执行(类似洋葱模型),即使你提前 return 响应,parent::handle() 之后的逻辑仍可能被调用;而 preHandle() 是前置钩子,返回 false 就彻底中断当前请求链,不进控制器、不走 postHandle()。
常见错误现象:
- 写了
if (! $user) return response()->json(['code'=>401]);放在handle()里,但接口依然执行了控制器方法 - 权限校验通过后没调用
parent::handle($request, $handler),导致响应体为空
正确做法是:在 preHandle() 中完成全部判断,返回 false 表示拦截,返回 true 表示放行。
preHandle() 里怎么安全获取当前用户
Webman 没有自动注入用户对象,也不能在构造函数里查 session 或 token —— 此时 $request 还未完成解析,$request->session() 可能为 null。
实操建议:
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 从
$request->header('authorization')提取 Bearer Token,再用JWT::parse()或自定义解码逻辑校验 - 若依赖 Session,先调用
$request->session()->start()(仅当 session 配置已启用) - 校验成功后,用
$request = $request->withAttribute('user', $user)注入用户,供后续中间件或控制器使用 - 务必检查
$request->getAttribute('user')是否存在,避免空对象调用方法报错
权限比对逻辑该放在哪?别硬编码路径
把 if ($path === '/admin/delete') { ... } 这类判断写死在中间件里,后期维护成本高、易出错、无法复用。
更合理的做法是结合路由定义做声明式控制:
- 在路由注册时添加
'permission' => 'user:delete'属性,例如:Route::delete('/users/{id}', [UserController::class, 'destroy'])->middleware(PermissionMiddleware::class)->option('permission', 'user:delete'); - 在
preHandle()中通过$request->route()->option('permission')获取所需权限标识 - 从 Redis 或内存缓存中查当前用户拥有的权限集合(如
user:123:permissions),用in_array()或array_intersect()判断是否匹配 - 对无
permission属性的路由默认放行(如登录、健康检查等白名单路径)
拦截后返回什么?注意 Accept 头与响应格式
直接 return response()->json(...) 在部分场景下会破坏前端预期,尤其当请求头 Accept: text/html 时返回 JSON,浏览器会显示原始字符串。
稳妥做法是根据 $request->header('accept') 动态响应:
- 包含
application/json→ 返回标准 JSON 格式:['code'=>403, 'message'=>'Forbidden'] - 匹配
text/html或为空 → 重定向到登录页:response()->redirect('/login?from='.urlencode($request->url())) - 所有拦截响应都应设置明确状态码:
401(未认证)、403(已认证但无权)
真正容易被忽略的是:权限变更后缓存未失效。Redis 中的权限列表更新了,但中间件仍读旧缓存——必须配合事件(如用户角色变更时 DEL user:123:permissions)或设置合理 TTL(建议 ≤5 分钟),并加降级逻辑(缓存失效时回查 DB,但需限流)。










