Laravel9 Sanctum分表认证后访问受保护路由报错
问题根因
报错Object of type Illuminate\Auth\AuthManager is not callable核心来自两个实现错误:
- 自定义账号密码校验通过后,没有调用Laravel官方登录方法把匹配到的用户实例绑定到认证守卫,Sanctum中间件解析请求用户时找不到合法的用户加载回调
- 默认Eloquent认证驱动会直接读取模型本身的密码字段,和你拆分到
UserPassword表的存储结构不兼容,且现有模型方法没有实现认证契约要求的密码读取逻辑
修复步骤
1. 修正登录控制器逻辑,校验通过后主动绑定用户
你现有逻辑只通过自定义类判断账号密码是否匹配,没有把查到的用户实例注入守卫上下文,直接调用$request->user()拿不到有效登录用户,token生成逻辑虽然能写入数据库,但没有和守卫的用户解析流程打通。把控制器方法修改为如下逻辑:
public function authenticate(Request $request) { $returnArray = [ 'success' => false, 'message' => null, 'userId' => null, 'token' => null, ]; if (Auth::check()) { $returnArray['message'] = 'ALREADY_LOGGED_IN'; $returnArray['userId'] = Auth::id(); return $returnArray; } // 匹配绑定了对应邮箱的用户 $user = UserMeta::whereHas('emailAddressList', function($query) use ($request) { $query->where('emailAddress', $request->emailAddress); })->first(); // 取最新密码记录做哈希校验 $latestPassword = $user?->passwordList()->latest()->first(); if (!$user || !$latestPassword || !Hash::check($request->password, $latestPassword->value)) { $returnArray['message'] = 'Invalid email address or password.'; return $returnArray; } // 核心步骤:将用户实例登录到Sanctum守卫 Auth::login($user); $token = $user->createToken('USER AUTHENTICATION TOKEN', ['*']); $returnArray['message'] = 'SUCCESS'; $returnArray['success'] = true; $returnArray['userId'] = $user->id; $returnArray['token'] = $token->plainTextToken; return $returnArray; }
2. 修正UserMeta模型,适配拆分表的认证逻辑
默认Eloquent用户提供者会调用模型的getAuthPassword()方法获取密码哈希,你需要重写该方法,适配密码存在关联表的结构,同时删掉原来写的错误关联取值方法:
<?php namespace App\Models\User; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; class UserMeta extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; protected $table = 'UserMeta'; // 重写密码读取逻辑,始终取最新的有效密码哈希 public function getAuthPassword() { return $this->passwordList()->latest()->value('value') ?? ''; } public function emailAddressList() { return $this->hasMany(UserEmail::class); } public function passwordList() { return $this->hasMany(UserPassword::class); } }
注意:你之前写的emailAddressLatest()、passwordLatest()方法逻辑错误,关联查询后直接读取属性不会返回正确结果,后续需要取最新邮箱/密码直接通过关联查询加value()方法取值即可。
3. 清除缓存避免旧配置干扰
执行以下命令清除框架缓存:
php artisan config:clear php artisan cache:clear
验证说明
修改完成后重新调用登录接口获取新token,携带Authorization: Bearer {你的token}请求头访问受保护路由即可正常返回用户信息,不会再抛出callable相关错误。后续实现密码回滚逻辑时,不需要修改认证核心代码,只要调整UserPassword表中对应记录的排序权重,让回滚的密码成为最新查询结果即可自动适配校验流程。
内容的提问来源于stack exchange,提问作者XLR
相关产品推荐
相关产品推荐

