jwt多用户退出的核心是让当前用户对应守卫的token失效,而非统一注销所有token;需按守卫(如api、admin)隔离黑名单,退出时将token加入对应守卫的redis黑名单键,并在自定义中间件中校验该守卫下的黑名单。

JWT 多用户退出时,关键不是“统一注销所有 token”,而是“让当前用户的 token 失效”,同时确保不同守卫(如 api、admin、web)互不干扰。Laravel 自带的 JWT 库(如 tymondesigns/jwt-auth 或更现代的 php-jwt + 自定义逻辑)本身不直接支持 token 吊销列表(RL),所以退出需结合黑名单(Blacklist)或数据库标记实现。
区分守卫的 JWT 退出核心逻辑
每个守卫对应独立的 token 存储/校验上下文。退出时必须:
- 从当前请求中解析出属于该守卫的 token(例如通过
auth:api中间件) - 获取该 token 对应的用户 ID 和守卫名(如
api或admin) - 将 token 加入**按守卫隔离的黑名单**(例如 Redis 键为
jwt:blacklist:api:{jti}) - 确保后续中间件在验证 token 时,检查对应守卫的黑名单
Laravel 控制器退出接口示例(多守卫兼容)
假设你使用 tymondesigns/jwt-auth(v1.x)并已配置多个守卫(api、admin),在 app/Http/Controllers/Auth/JwtAuthController.php 中:
namespace App\Http\Controllers\Auth;
<p>use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Illuminate\Support\Facades\Redis;</p><p>class JwtAuthController extends Controller
{
public function logout(Request $request)
{
$guard = auth()->getGuardName(); // 自动获取当前激活的守卫:'api' 或 'admin'</p><pre class="brush:php;toolbar:false;"> try {
$token = JWTAuth::parseToken();
$payload = $token->getPayload();
$jti = $payload['jti'] ?? md5($payload->toJson()); // 唯一 token 标识
// 黑名单键按守卫隔离
$blacklistKey = "jwt:blacklist:{$guard}:{$jti}";
Redis::setex($blacklistKey, config('jwt.ttl') * 60, 1); // 有效期同 token TTL
return response()->json(['message' => 'Successfully logged out']);
} catch (TokenInvalidException $e) {
return response()->json(['error' => 'Token already invalid'], 400);
}
}}
自定义 JWT 黑名单中间件(守卫感知)
默认中间件不区分守卫,需重写验证逻辑。创建 app/Http/Middleware/CheckJwtBlacklist.php:
namespace App\Http\Middleware;
<p>use Closure;
use Tymon\JWTAuth\Facades\JWTAuth;
use Illuminate\Support\Facades\Redis;</p><p>class CheckJwtBlacklist
{
public function handle($request, Closure $next)
{
$guard = auth()->getGuardName();
$token = JWTAuth::parseToken()->getToken();
$jti = JWTAuth::getPayload($token)['jti'] ?? md5($token->__toString());</p><pre class="brush:php;toolbar:false;"> $blacklistKey = "jwt:blacklist:{$guard}:{$jti}";
if (Redis::exists($blacklistKey)) {
throw new \Tymon\JWTAuth\Exceptions\TokenInvalidException('Token blacklisted for guard: ' . $guard);
}
return $next($request);
}}
然后在 app/Http/Kernel.php 中注册中间件,并在对应守卫路由组中使用:
// 在 $middlewareGroups['api'] 或自定义 admin group 中添加 'jwt.blacklist' => \App\Http\Middleware\CheckJwtBlacklist::class,
路由定义示例(区分守卫)
确保不同守卫走不同路由,触发对应守卫认证和退出逻辑:
// api routes (guard = 'api')
Route::middleware('auth:api')->group(function () {
Route::post('/logout', [JwtAuthController::class, 'logout']);
});
<p>// admin routes (guard = 'admin')
Route::prefix('admin')->middleware('auth:admin')->group(function () {
Route::post('/logout', [JwtAuthController::class, 'logout']);
});</p>
这样,调用 /api/logout 会使用 api 守卫上下文退出,调用 /admin/logout 则使用 admin 守卫,互不影响。











