You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 12中使用中间件保护/api/admin/* API路由时持续返回403 Forbidden的问题求助

Laravel 12中使用中间件保护/api/admin/* API路由时持续返回403 Forbidden的问题求助

各位好,我目前在做一个基于Laravel 12 + Vue SPA的项目,用Sanctum做身份认证。现在想通过中间件保护/api/admin/*的路由,但无论怎么调整配置,访问这些路由都会返回403 | FORBIDDEN,想请大家帮忙排查问题。

先说说我目前的实现:

已做的配置

  1. Admin中间件:用来校验用户是否有admin_access权限
// app/Http/Middleware/Admin.php
public function handle(Request $request, Closure $next): Response {
    abort_if(Gate::denies('admin_access'), 403);
    return $next($request);
}
  1. AuthGates中间件:动态根据用户角色和权限定义Gate规则
// app/Http/Middleware/AuthGates.php
public function handle(Request $request, Closure $next): mixed {
    $user = auth()->user();
    if ($user) {
        $roles = Role::with('permissions')->get();
        $permissionsArray = [];
        foreach ($roles as $role) {
            foreach ($role->permissions as $permission) {
                $permissionsArray[$permission->title][] = $role->id;
            }
        }
        foreach ($permissionsArray as $title => $roles) {
            Gate::define($title, function (User $user) use ($roles) {
                return count(array_intersect($user->roles->pluck('id')->toArray(), $roles)) > 0;
            });
        }
    }
    return $next($request);
}
  1. 中间件注册:在bootstrap/app.php里配置了中间件
->withMiddleware(function (Middleware $middleware) {
    $middleware->appendToGroup('api', [
        AuthGates::class,
    ]);
    $middleware->append(Admin::class); // 这里把Admin设为了全局中间件
    $middleware->statefulApi();
})
  1. 路由配置:用auth:sanctum和Admin中间件保护admin路由
Route::middleware('auth:sanctum')->group(function () {
    // ...其他路由
    Route::prefix('admin')->group(function () {
        Route::prefix('users')->group(function () {
            Route::get('/', [AdminUserController, 'index']);
            // ...其他用户路由
        });
    })->middleware(Admin::class);
});

问题现象

不管当前登录用户有没有admin_access权限,访问/api/admin/users这类路由都会直接返回403,完全没达到预期的权限校验效果。

排查方向与解决方案

经过反复测试,我梳理出几个可能的问题点和对应的解决办法:

1. 中间件执行顺序错误(最可能的根因)

我把Admin::class注册成了全局中间件($middleware->append(Admin::class)),而全局中间件的执行顺序是在路由组中间件之前的。也就是说,当请求到达时:

  • 全局的Admin中间件先执行,这时候AuthGates中间件还没运行(它属于api组中间件,在路由阶段才会执行)
  • 此时admin_access这个Gate还没被定义,Gate::denies('admin_access')会默认返回true,直接触发403

解决办法:
删掉全局中间件注册里的$middleware->append(Admin::class);,因为我们已经在路由组里显式指定了Admin中间件。这样Admin中间件只会在路由组阶段执行,而此时AuthGates已经完成了Gate的定义,权限校验就能正常工作了。

2. 验证Gate定义的准确性

如果调整顺序后还是有问题,可以在Admin中间件里临时添加调试代码,确认Gate的状态:

public function handle(Request $request, Closure $next): Response {
    // 调试用:打印当前用户和Gate校验结果
    dump(auth()->user()?->roles->pluck('id'));
    dump(Gate::has('admin_access')); // 看admin_access是否被正确定义
    dump(Gate::allows('admin_access')); // 看当前用户是否有权限

    abort_if(Gate::denies('admin_access'), 403);
    return $next($request);
}

通过这些输出可以快速定位是Gate没定义,还是用户权限不匹配。

3. 检查权限名称的大小写和一致性

确保数据库里permissions表的title字段值是完全小写的admin_access,和Gate::denies('admin_access')里的字符串完全一致,大小写敏感会导致Gate匹配失败。

4. 确认用户已正确认证

虽然路由用了auth:sanctum,但要确保请求头里带了正确的Authorization: Bearer {token},或者是状态域请求(因为开启了statefulApi()),保证auth()->user()能拿到当前登录用户。如果用户未认证,AuthGates不会定义任何Gate,同样会触发403。

总结

最核心的问题大概率是中间件执行顺序导致的,全局Admin中间件先于AuthGates运行,导致Gate未定义就触发了权限校验。调整中间件注册方式后应该就能解决问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:04:28