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

Laravel5如何动态获取用户类类型?JWTAuth返回结果异常问题

解决JWT认证中无法自动识别用户模型类型的问题

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:31:10