权限不生效的核心原因是登录态未适配token、权限节点名与路由规则名不一致、中间件未正确绑定api路由分组。需改用jwt载入permissions字段校验,路由显式命名如api.user.list,中间件精准注册到api分组并确保return $next($request)。

前后端分离下权限角色分配不生效,核心问题不是前端没显示按钮,而是后端鉴权根本没触发或校验逻辑失效。关键在三点:登录态不兼容、权限节点名错位、中间件未覆盖 API 路由。
登录态必须脱离 Session,改用 Token 传权限
ThinkPHP 默认 Auth::check() 依赖 session('think_auth'),但前后端分离时前端通常用 JWT 或自定义 token 认证,Session 不会自动建立——结果 Auth::check() 恒为 false,跟角色配没配权限完全无关。
- API 接口中间件里禁止调 Auth::check('admin/user/list'),它底层仍查 session 缓存
- 登录成功后,直接把用户权限数组(如 ['user:list', 'article:delete'])签入 JWT payload,字段建议命名为 permissions
- 接口中间件中用 $token = $request->header('authorization') 解析 token,再从 payload 取 permissions 数组做 in_array 判断
- 别把权限塞进 Redis 缓存再查——接口要低延迟,O(1) 判断优于一次网络 IO
权限节点名必须与路由规则名严格对齐
前后端分离常把后台路由全改成 /api/v1/xxx 形式,但权限节点名若还写 admin/user/list,Auth::check() 就永远匹配不上。
- 路由定义必须显式绑定规则名:Route::get('api/v1/user/list', 'api.v1.UserController@list')->name('api.user.list');
- 对应权限节点名只能是 api.user.list(点号分隔),不能是 api/user/list、user_list 或中文
- 调试时在中间件加 dump($request->rule()->getName()),确认输出和 auth_rule.name 完全一致(包括大小写、有无前缀)
- 前端按钮权限标识(如 v-if="hasPermission('api.user.list')")必须和服务端节点名一字不差
中间件必须精准注册到 API 路由分组
很多人把 rbac 中间件加在全局 middleware.php,但它对 /api/ 开头的路由无效——因为 ThinkPHP 的中间件绑定是按路由分组来的,不是“全站拦截”。
- 在 app/middleware.php 中只配置分组中间件:return ['api' => ['app\middleware\ApiAuth::class']]
- 路由定义必须明确归属该分组:Route::group('api', function () { Route::get('v1/user', 'api.v1.User@index'); })->middleware('api');
- 白名单路径(如 /api/v1/login)要在 ApiAuth 中间件内 hardcode 判断,不能靠配置文件——避免因配置加载顺序漏放行
- 检查中间件 handle() 方法末尾是否写了 return $next($request),漏写会导致请求静默终止,表面看像没权限,实则是中断了
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











