Laravel5如何动态获取用户类类型?JWTAuth返回结果异常问题
Hey there! Let's tackle this issue where you're only getting User returned from class_basename(JWTAuth::toUser($token)) even when the user is actually a BusinessUser—and you don't want to split your routes to handle different guards. Here are a couple of practical solutions:
问题根源
Right now, your api guard is configured to use the users provider, which is tied exclusively to the User model. When you call JWTAuth::toUser($token), it defaults to using the api guard, so it only looks up users in the User model, ignoring BusinessUser entirely.
方案1:手动解析Token并匹配对应模型
This is a quick fix that doesn't require modifying guard configurations. You can parse the token's payload to get the user ID, then check both models to find the correct instance:
use Tymon\JWTAuth\Facades\JWTAuth; /** * Get the authenticated user instance, matching either User or BusinessUser * @param string $token JWT token * @return \Illuminate\Contracts\Auth\Authenticatable|null */ function resolveAuthenticatedUser(string $token) { // Extract the user ID from the token payload $payload = JWTAuth::getPayload($token); $userId = $payload->get('sub'); // First check for BusinessUser $businessUser = \App\Models\BusinessUser::find($userId); if ($businessUser) { return $businessUser; } // Fall back to regular User return \App\Models\User::find($userId); } // Usage example $user = resolveAuthenticatedUser($token); echo class_basename($user); // Will output "BusinessUser" or "User" as appropriate
Note: Make sure both User and BusinessUser models implement the Illuminate\Contracts\Auth\Authenticatable interface (which they should if they're set up for auth already). Also, ensure user IDs don't overlap between the two models (e.g., use separate databases or prefix IDs) to avoid mismatches.
方案2:创建通用用户提供者(更优雅的长期方案)
If you want to integrate this directly with Laravel's auth system so JWTAuth::toUser() works out of the box, you can build a combined user provider that checks both models:
Step 1: Add a new provider to config/auth.php
'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'business_users' => [ 'driver' => 'eloquent', 'model' => App\Models\BusinessUser::class, ], // Add this combined provider 'combined_users' => [ 'driver' => 'combined', // We'll register this driver next 'models' => [ App\Models\BusinessUser::class, App\Models\User::class, ], ], ],
Step 2: Create the combined user provider class
Make a new class App/Models/CombinedUserProvider.php:
namespace App\Models; use Illuminate\Auth\EloquentUserProvider; use Illuminate\Contracts\Auth\Authenticatable; class CombinedUserProvider extends EloquentUserProvider { protected array $models; public function __construct($hasher, array $config) { parent::__construct($hasher, $config); $this->models = $config['models']; } /** * Retrieve a user by their unique identifier. * * @param mixed $identifier * @return Authenticatable|null */ public function retrieveById($identifier) { foreach ($this->models as $modelClass) { $user = $this->createModel($modelClass)->newQuery()->find($identifier); if ($user) { return $user; } } return null; } /** * Create a new instance of the model. * * @param string $modelClass * @return Authenticatable */ protected function createModel(string $modelClass): Authenticatable { $model = app($modelClass); if (! $model instanceof Authenticatable) { throw new \RuntimeException( "Class {$modelClass} must implement Illuminate\Contracts\Auth\Authenticatable" ); } return $model; } }
Step 3: Register the custom provider driver
In App/Providers/AuthServiceProvider.php, add this to the boot() method:
use App\Models\CombinedUserProvider; use Illuminate\Support\Facades\Auth; public function boot() { $this->registerPolicies(); // Register the combined user provider driver Auth::provider('combined', function ($app, array $config) { return new CombinedUserProvider($app['hash'], $config); }); }
Step 4: Update your api guard to use the combined provider
Modify the api guard in config/auth.php:
'api' => [ 'driver' => 'token', 'provider' => 'combined_users', // Switch to our new provider ],
Now when you call JWTAuth::toUser($token), it will automatically check both BusinessUser and User models and return the correct instance—no need for separate routes!
内容的提问来源于stack exchange,提问作者Seio. E.

