tymondesigns/jwt-auth的attempt方法始终返回false问题求助
我来帮你排查这个JWTAuth::attempt()始终返回false的问题,结合你用bcrypt加密的场景,大概率是凭证匹配逻辑或者模型配置的问题,咱们一步步来解决:
attempt()的默认逻辑(关键!) JWTAuth::attempt()方法默认是按照email和password这两个字段来验证的——它会先找对应email的用户,再用bcrypt比对password字段的哈希值。但你现在用的是mobile和code作为凭证,这就导致默认逻辑找不到匹配的字段,自然返回false。
解决这个问题有两种思路:
思路一:手动验证+生成令牌
跳过attempt(),自己完成用户查找和密码比对,再手动生成令牌,代码可以改成这样:
use Illuminate\Support\Facades\Hash; use Tymon\JWTAuth\Facades\JWTAuth; $credentials = $request->only('mobile', 'code'); // 第一步:通过mobile找到对应的用户 $user = \App\Models\User::where('mobile', $credentials['mobile'])->first(); // 第二步:验证用户存在,且code(密码)的哈希匹配 if (!$user || !Hash::check($credentials['code'], $user->password)) { return response()->json(['error' => 'invalid_credentials'], 401); } // 第三步:手动为用户生成JWT令牌 $token = JWTAuth::fromUser($user); return response()->json(compact('token'));
思路二:重写用户模型的验证字段
如果你想继续用attempt()方法,可以在User模型里重写getAuthPassword()方法,同时指定登录字段:
// User模型文件 use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Model implements JWTSubject { // 必须实现的JWT接口方法 public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return []; } // 重写这个方法,返回你存储bcrypt哈希的字段(比如你的password字段) public function getAuthPassword() { return $this->password; // 这里要和你数据库里存哈希的字段对应 } }
然后调用attempt()时,需要把code映射为password字段,让方法能识别:
// 在你的控制器里 $credentials = $request->only('mobile', 'code'); // 调整字段名,适配attempt()的默认逻辑 $credentials['password'] = $credentials['code']; unset($credentials['code']); try { if (! $token = JWTAuth::attempt($credentials)) { return response()->json(['error' => 'invalid_credentials'], 401); } } catch (JWTException $e) { return response()->json(['error' => 'could_not_create_token'], 500); } return response()->json(compact('token'));
一定要确保你在存储用户密码(code)的时候,是用bcrypt()或者Hash::make()加密的,比如创建用户时:
// 正确的加密方式 $user = new \App\Models\User(); $user->mobile = $request->mobile; $user->password = bcrypt($request->code); // 或者 Hash::make($request->code) $user->save();
如果存的时候是明文,或者用了其他加密方式,那Hash::check()肯定比对失败,attempt()也会返回false。
别忘了你的User模型必须实现Tymon\JWTAuth\Contracts\JWTSubject接口,也就是上面代码里的那两个方法——这是JWT扩展正常工作的前提,少了的话不仅attempt()会出问题,生成令牌也会失败。
如果你的用户表有类似status(是否启用)的字段,attempt()默认不会检查这个,所以如果用户被禁用了,也会返回false。这种情况可以在查找用户时加上状态判断:
$user = \App\Models\User::where('mobile', $credentials['mobile']) ->where('status', 1) // 假设1代表启用状态 ->first();
内容的提问来源于stack exchange,提问作者Sugan Zhang

