Laravel 10+MongoDB下Sanctum生成Token遇prepare() on null错误
Laravel 10 + MongoDB 生成Sanctum Token时报错:Call to a member function prepare() on null
问题描述
我有一个使用MongoDB数据库的Laravel 10应用,正在为api_users集合中的用户创建生成Token的API端点。创建用户的函数运行完全正常,但调用createToken生成Token时触发错误。
创建用户的正常代码
public function createApiUser(Request $request) { $username = $request->input('username'); $password = $request->input('password'); $password = Hash::make($password); $apiUser = new ApiUser(); $apiUser->username = $username; $apiUser->password = $password; try { $apiUser->save(); return ["Success"]; } catch (\Throwable $th) { return ["error" => $th->getMessage()]; } }
生成Token的报错代码
public function generateToken(Request $request) { $username = $request->input('username'); $password = $request->input('password'); $collection = DB::connection('mongodb')->collection('api_users'); // 根据用户名获取用户文档 $userData = ApiUser::where('username', $username)->first(); if ($userData && Hash::check($password, $userData['password'])) { $user = $userData; // 执行此行时触发错误 $token = $user->createToken('MyApp')->plainTextToken; return response()->json([ 'token' => $token, 'user' => $user, ], 200); } return response()->json(['error' => 'Unauthorised'], 401); }
错误信息
Error: Call to a member function prepare() on null in file /vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 574
ApiUser模型代码
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use MongoDB\Laravel\Eloquent\Model as Eloquent; use MongoDB\Laravel\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Model; use Laravel\Sanctum\HasApiTokens; class ApiUser extends Eloquent { use HasApiTokens, HasFactory,Notifiable; protected $guard = 'api'; protected $table = 'api_users'; protected $connection = 'mongodb'; protected $guarded = []; protected $fillable = [ 'username', 'password', ]; }
auth.php配置
<?php return [ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', 'email' => [ 'driver' => 'session', 'provider' => 'users', ], ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'mongodb' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'sanctum', 'provider' => 'api_users', ], 'api_users' => [ 'driver' => 'sanctum', 'provider' => 'api_users', ], ], 'verification' => [ 'enabled' => false, 'expire' => 60, ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'api_users' => [ 'driver' => 'eloquent', 'model' => App\Models\ApiUser::class, ], ], 'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_resets', 'expire' => 60, 'throttle' => 60, ], ], 'password_timeout' => 10800, ];
解决方案
问题根源
错误是因为Laravel Sanctum默认使用默认数据库连接(通常为MySQL)存储Token,但你的ApiUser模型使用MongoDB连接,导致Sanctum尝试用错误的连接操作Token表。
修复步骤
修正ApiUser模型继承关系
移除多余的模型引用,直接继承MongoDB提供的Authenticatable类,确保认证契约正确实现:<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use MongoDB\Laravel\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; class ApiUser extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; protected $guard = 'api'; protected $table = 'api_users'; protected $connection = 'mongodb'; protected $guarded = []; protected $fillable = [ 'username', 'password', ]; }配置Sanctum使用MongoDB连接
发布Sanctum配置文件(如果未发布):php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"在
config/sanctum.php中指定数据库连接为mongodb:return [ // 其他配置... 'database_connection' => env('SANCTUM_DB_CONNECTION', 'mongodb'), // 其他配置... ];确保MongoDB连接配置正确
检查.env文件中的MongoDB连接参数:DB_CONNECTION=mongodb DB_HOST=127.0.0.1 DB_PORT=27017 DB_DATABASE=your_database_name DB_USERNAME= DB_PASSWORD=重新生成Sanctum迁移(可选)
如果之前用MySQL创建过Sanctum迁移,删除相关文件后运行MongoDB迁移:php artisan mongodb:migrate简化generateToken方法
优化代码,直接使用模型查询:public function generateToken(Request $request) { $request->validate([ 'username' => 'required', 'password' => 'required', ]); $user = ApiUser::where('username', $request->username)->first(); if (!$user || !Hash::check($request->password, $user->password)) { return response()->json(['error' => 'Unauthorised'], 401); } $token = $user->createToken('MyApp')->plainTextToken; return response()->json([ 'token' => $token, 'user' => $user, ], 200); }
内容的提问来源于stack exchange,提问作者bob269
相关产品推荐
相关产品推荐

