laravel多表jwt鉴权关键在于守卫(guard)与模型解耦,需为users、admins、clients等各表配置独立guard和provider,结合sanctum管理生命周期、firebase/php-jwt手动签发含type声明的token,并通过自定义中间件动态切换guard实现路由级鉴权隔离。

在 Laravel 中实现多表用户(比如 users、admins、clients)共用 JWT 鉴权,关键不是“改一个包”,而是让认证守卫(Guard)能按需识别不同模型、不同表、不同登录逻辑。Laravel 默认只配一个 provider,但多表场景下必须解耦“谁来验证”和“从哪查用户”。以下为适用于 Laravel 9/10/11 的完整、可落地、无废弃依赖配置方案。
一、统一使用 Sanctum + 手动 JWT 签发(推荐基础架构)
放弃已停止维护的 tymon/jwt-auth(Laravel 9+ 兼容性差、报错多),改用官方持续更新的 laravel/sanctum 管理 token 生命周期与中间件,再用 firebase/php-jwt 签发标准 JWT——既安全又可控。
- 安装 Sanctum:
composer require laravel/sanctum,运行php artisan sanctum:install - 安装 JWT 库:
composer require firebase/php-jwt - 确保
config/auth.php中默认 guard 是api,且其 driver 为sanctum - 不启用 Sanctum 的默认 token 创建逻辑,而是自己构造 JWT 响应(保留自定义 payload 能力)
二、为每张用户表定义独立 Provider 和 Guard
例如你有 users(前台会员)、admins(后台管理员)、clients(B2B 客户),需分别配置:
- 在
config/auth.php的'guards'下新增三项:
'user_api' => ['driver' => 'jwt', 'provider' => 'users'],<br>'admin_api' => ['driver' => 'jwt', 'provider' => 'admins'],<br>'client_api' => ['driver' => 'jwt', 'provider' => 'clients']
- 在
'providers'下对应添加:
'users' => ['driver' => 'eloquent', 'model' => App\Models\User::class],<br>'admins' => ['driver' => 'eloquent', 'model' => App\Models\Admin::class],<br>'clients' => ['driver' => 'eloquent', 'model' => App\Models\Client::class]
- 每个模型都需实现
Authenticatable,并确保密码字段名、验证逻辑一致(如都用password字段 +Hash::check())
三、自定义 JWT 签发逻辑(支持多模型、多声明)
登录控制器中不再调用 $user->createToken(),而是手动构建 JWT:
- 引入
use Firebase\JWT\JWT;和use Illuminate\Support\Str; - 根据请求类型(如
type=user或type=admin)动态加载对应模型 - 签发时写入区分身份的 claim,例如:
$payload = [<br> 'sub' => $user->id,<br> 'type' => $userType, // 'user' / 'admin' / 'client'<br> 'role' => $user->role ?? 'default',<br> 'iat' => time(),<br> 'exp' => time() + 3600,<br> 'jti' => (string) Str::uuid(),<br>];<br>$token = JWT::encode($payload, config('app.jwt_secret'), 'HS256');
-
app.jwt_secret需在.env中设置(如JWT_SECRET=base64:xxx),并确保密钥强度足够
四、扩展认证中间件,支持多 guard 动态切换
默认 auth:api 只认一个 guard,要支持路由级指定,需创建自定义中间件:
- 运行
php artisan make:middleware AuthenticateMultiGuard - 在
handle()中解析请求 header 或 query 参数(如X-Guard: admin_api) - 调用
Auth::guard($guardName)->user()获取对应模型实例 - 若验证失败,返回 401;成功则将用户绑定到 request,供后续控制器使用
然后在路由中灵活使用:
Route::post('/admin/login', [AdminController::class, 'login'])->middleware('auth.multi:admin_api');<br>Route::get('/user/profile', [UserController::class, 'profile'])->middleware('auth.multi:user_api');
不复杂但容易忽略:多表 JWT 的核心不在 token 本身,而在于守卫如何映射模型、中间件如何选择守卫、签发时如何注入上下文标识。只要这三层对齐,就能干净分离权限边界,避免混用或越权访问。











