laravel jwt认证支持多用户类型需为每类用户配置独立guard及provider。1.在auth.php中定义多个jwt guard并绑定唯一provider;2.配置对应provider及模型,模型需实现jwtsubject接口;3.所有认证操作须显式指定guard;4.路由中间件需明确guard名;5.黑名单必须按guard隔离,避免token误删。

要让 Laravel 的 JWT 认证支持多个用户类型(比如 users、admins、merchants),关键不是改一个配置,而是为每类用户建立独立、隔离的 guard 分组。整个过程围绕 guard 与 provider 的严格绑定展开,漏掉任一环节都容易出现“登录成功但拿不到用户”“admin 登录踢掉 user”这类问题。
1. 在 auth.php 中定义多个 JWT guard
打开 config/auth.php,在 'guards' 数组里新增对应守卫,驱动统一用 jwt,但 provider 名必须唯一且一一对应:
'admin' => ['driver' => 'jwt', 'provider' => 'admins']'merchant' => ['driver' => 'jwt', 'provider' => 'merchants']- 保留默认的
'api' => ['driver' => 'jwt', 'provider' => 'users'](供普通用户使用)
注意:guard 名(如 admin)后续会在中间件、登录逻辑、刷新接口中显式调用,不能拼错。
2. 配置对应 provider 并确认模型可用
继续在 config/auth.php 的 'providers' 部分添加:
'admins' => ['driver' => 'eloquent', 'model' => App\Models\Admin::class]'merchants' => ['driver' => 'eloquent', 'model' => App\Models\Merchant::class]
确保每个模型真实存在,并满足以下要求:
- 继承
Authenticatable - 实现
JWTSubject接口 - 正确重写
getJWTIdentifier()(通常返回$this->getKey()) - 在
getJWTCustomClaims()中加入区分字段,例如:['guard' => 'admin']
3. 登录、刷新、登出必须显式指定 guard
所有认证操作都不能依赖默认守卫,否则会走错表、用错黑名单:
- 登录:
Auth::guard('admin')->login($admin)(不是Auth::login()) - 获取当前用户:
Auth::guard('admin')->user() - 刷新 token:
Auth::guard('admin')->refresh()(不加 guard 会默认走 api,payload 混乱) - 登出:
Auth::guard('admin')->logout()(避免误删其他 guard 的 token)
控制器方法示例:
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (!$token = Auth::guard('admin')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
4. 中间件和路由必须带 guard 名
保护路由时,中间件格式为 auth:admin 或 auth:merchant,不能只写 auth:api 或 auth:
Route::middleware('auth:admin')->get('/admin/profile', [AdminController::class, 'profile']);Route::middleware('auth:merchant')->post('/order', [OrderController::class, 'store']);
若需多个 guard 共享某组路由(如“任一后台角色都可访问”),可用逗号分隔:middleware('auth:admin,merchant'),Laravel 会顺序尝试,任一通过即放行。
5. 黑名单 key 必须按 guard 隔离
tymon/jwt-auth 默认黑名单是全局共享的,这会导致 admin 登出时误删 user 的 token。解决方式是让黑名单缓存 key 带 guard 上下文:
- 重写
JWTBlacklist::add()方法,在生成 cache key 时拼入$payload['guard'] - 或在
getJWTCustomClaims()返回的数组中固定注入'guard' => 'admin',再在自定义黑名单逻辑中读取该字段 - 数据库黑名单表(如
blacklist)建议增加guard字段,用于查询过滤
不隔离黑名单,就等于把不同身份的门禁卡放在同一个挂失系统里——挂一张,全作废。











