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

Laravel REST API多设备用户认证及JWT令牌吊销方案咨询

Hey there! Let's walk through a practical, Laravel-native approach to handle multi-device authentication with JWT—including proper token revocation for full account bans. I’ve implemented similar setups for mobile + web APIs before, so here’s what works:

1. Database Table Design

First, you’ll need a dedicated table to track active device tokens for users. Let’s call it user_device_tokens (create a model UserDeviceToken for it too). Here’s the schema:

  • id: Primary key
  • user_id: Foreign key to your users table
  • device_id: Unique identifier for the device (e.g., a UUID generated by the mobile/web app, or a device fingerprint)
  • token_hash: Hashed version of the JWT (never store raw JWTs—use SHA-256 or Laravel’s Hash facade)
  • expires_at: DateTime for token expiration
  • is_revoked: Boolean flag to mark revoked tokens
  • created_at/updated_at: Timestamps

Add the Eloquent relationship to your User model:

public function deviceTokens()
{
    return $this->hasMany(UserDeviceToken::class);
}
2. Token Generation Logic

When a user logs in from a device, generate a JWT that includes both user_id (as the standard sub claim) and device_id (a custom claim). Then store the hashed token in your user_device_tokens table.

Example code (in an auth service or controller):

use Illuminate\Support\Facades\Hash;
use Tymon\JWTAuth\Facades\JWTAuth;

public function generateToken(User $user, string $deviceId)
{
    // Generate JWT with device_id claim
    $token = JWTAuth::claims(['device_id' => $deviceId])->fromUser($user);
    
    // Store hashed token and device info
    $user->deviceTokens()->create([
        'device_id' => $deviceId,
        'token_hash' => Hash::make($token),
        'expires_at' => now()->addDays(7), // Adjust expiration as needed
        'is_revoked' => false
    ]);
    
    return $token;
}
3. Token Revocation (Single Device & Full Account Ban)

Single Device Revocation

To revoke a token for a specific device, just update the is_revoked flag for that user-device pair:

public function revokeDeviceToken(User $user, string $deviceId)
{
    $user->deviceTokens()
        ->where('device_id', $deviceId)
        ->update(['is_revoked' => true]);
}

Full Account Ban

For a complete account-wide ban, combine two steps for robustness:

  1. Add an is_banned boolean field to your users table (quick global check)
  2. Revoke all active tokens for the user

Example code:

public function banUser(User $user)
{
    // Mark user as banned to block future logins
    $user->update(['is_banned' => true]);
    
    // Revoke all active device tokens
    $user->deviceTokens()->update(['is_revoked' => true]);
}
4. Request Validation Middleware

Create a custom middleware to validate every incoming API request. This middleware will:

  • Parse the JWT to get user_id and device_id
  • Check if the user is banned
  • Verify the token exists in user_device_tokens, is not revoked, and hasn’t expired

Create app/Http/Middleware/CheckValidDeviceToken.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Hash;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class CheckValidDeviceToken
{
    public function handle($request, Closure $next)
    {
        try {
            // Parse JWT and extract claims
            $token = JWTAuth::parseToken();
            $payload = $token->getPayload();
            $userId = $payload->get('sub');
            $deviceId = $payload->get('device_id');
            $rawToken = $request->bearerToken();
            
            // Check if user is banned
            $user = \App\Models\User::findOrFail($userId);
            if ($user->is_banned) {
                return response()->json(['message' => 'Account has been banned'], 401);
            }
            
            // Validate token is active and valid
            $tokenRecord = $user->deviceTokens()
                ->where('device_id', $deviceId)
                ->where('is_revoked', false)
                ->where('expires_at', '>', now())
                ->first();
            
            if (!$tokenRecord || !Hash::check($rawToken, $tokenRecord->token_hash)) {
                return response()->json(['message' => 'Invalid or revoked token'], 401);
            }
            
        } catch (JWTException $e) {
            return response()->json(['message' => 'Unauthorized'], 401);
        }
        
        return $next($request);
    }
}

Register the middleware in app/Http/Kernel.php:

protected $routeMiddleware = [
    // ... other middleware
    'auth.device' => \App\Http\Middleware\CheckValidDeviceToken::class,
];

Apply it to your API routes:

Route::middleware('auth.device')->group(function () {
    // Your protected API routes here
});
5. Extra Optimizations
  • Clean up expired tokens: Create a Laravel scheduled task to delete records where expires_at < now() daily—keeps your database lean.
  • Device metadata: Add fields like device_name, os, or browser to user_device_tokens so users can view/manage their active devices (e.g., a web dashboard to revoke old devices).
  • Refresh tokens: Implement a refresh token flow (store refresh tokens in the same table or a separate one) to let users get new access tokens without re-logging in.
  • Avoid duplicate tokens: Before generating a new token, check if the user already has an active, unrevoked token for that device—return the existing one instead of creating a new one.

内容的提问来源于stack exchange,提问作者Tahar Moustalik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:57:12