laravel jwt多用户权限拦截需区分用户表token并细粒度控制:1.各模型通过getjwtcustomclaims()注入guard标识;2.自定义checkjwtguard中间件校验payload中guard值;3.路由按guard分组绑定jwt.auth与jwt.guard中间件;4.gate权限闭包中严格判断模型实例类型。

要实现 Laravel 中 JWT 多用户接口的权限拦截,核心是解决两个问题:一是区分不同用户表(如 users、admins)生成的 Token 不混用;二是对不同守卫(guard)下的请求做细粒度权限控制(如“仅管理员可访问 /admin/users”)。下面给出完整、可直接落地的代码结构,不含冗余说明,聚焦关键文件与逻辑。
1. 多用户模型隔离:为每个用户表添加自定义 claim
以 Admin 模型为例(app/Models/Admin.php):
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class Admin extends Authenticatable implements JWTSubject
{
protected $table = 'admins';
protected $guarded = [];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
// 关键:标识该 token 来自 admins 表
return ['guard' => 'admin'];
}
}
User 模型同理,返回 ['guard' => 'web'] 或 ['guard' => 'api'],确保字段值唯一且可识别。
2. 自定义中间件:校验 Token 中的 guard 声明
运行:php artisan make:middleware CheckJwtGuard
编辑 app/Http/Middleware/CheckJwtGuard.php:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Facades\JWTAuth;
class CheckJwtGuard
{
public function handle(Request $request, Closure $next, string $expectedGuard)
{
try {
$token = JWTAuth::parseToken();
$payload = $token->getPayload();
// 从 payload 提取自定义 guard 字段
$actualGuard = $payload['guard'] ?? null;
if ($actualGuard !== $expectedGuard) {
return response()->json([
'message' => 'Invalid token guard'
], 401);
}
} catch (JWTException $e) {
return response()->json([
'message' => 'Token is invalid or expired'
], 401);
}
return $next($request);
}
}
在 app/Http/Kernel.php 的 $routeMiddleware 中注册:
'jwt.guard' => \App\Http\Middleware\CheckJwtGuard::class,
```
3. 路由分组 + 守卫绑定 + 权限检查
在 routes/api.php 中:
// 管理端接口(强制 token 来自 admins 表)
Route::prefix('admin')->group(function () {
Route::middleware(['jwt.auth', 'jwt.guard:admin'])->group(function () {
Route::get('/dashboard', [AdminController::class, 'dashboard']);
Route::get('/users', [AdminController::class, 'listUsers'])
->middleware('can:manage-users'); // 使用 Gate 权限
});
});
// 用户端接口(强制 token 来自 users 表)
Route::prefix('api')->group(function () {
Route::middleware(['jwt.auth', 'jwt.guard:api'])->group(function () {
Route::get('/profile', [UserController::class, 'profile']);
Route::post('/comment', [PostController::class, 'store'])
->middleware('can:create-comment');
});
});
```
4. Gate 权限定义(支持多用户类型)
在 app/Providers/AuthServiceProvider.php 的 boot() 方法中:
use Illuminate\Support\Facades\Gate;
Gate::define('manage-users', function ($user) {
// 区分模型类型,避免 User 和 Admin 混淆
return $user instanceof \App\Models\Admin && $user->role === 'super_admin';
});
Gate::define('create-comment', function ($user) {
return $user instanceof \App\Models\User && $user->status === 'active';
});
```
注意:权限闭包中必须显式判断模型实例类型,不能只依赖 $user->role —— 因为不同表可能有同名字段,但含义完全不同。
5. 登录控制器示例(带 guard 标识写入)
app/Http/Controllers/AdminController.php:
use Tymon\JWTAuth\Facades\JWTAuth;
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (!$token = auth('admin')->attempt($credentials)) {
return response()->json(['message' => 'Unauthorized'], 401);
}
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('admin')->factory()->getTTL() * 60
]);
}
```
其中 auth('admin') 对应 config/auth.php 中已配置的 admin guard,驱动为 jwt,provider 指向 admins 模型。
不复杂但容易忽略:所有中间件顺序必须是 jwt.auth 在前、jwt.guard 在后;Gate 权限判断必须基于具体模型类而非通用 Auth::user() 返回值类型;Token 一旦签发就不可更改 claim,所以登录时务必确保 getJWTCustomClaims() 返回正确值。











