Laravel密码重置报错:WHERE子句中不存在email列
Laravel密码重置使用手机号时出现「email字段不存在」错误
问题描述
尝试通过phone_number字段实现密码重置功能,已创建包含phone_number主键的password_reset_tokens表,但调用重置接口时出现以下错误:
Column not found: 1054 Unknown column 'email' in 'where clause' (Connection: mysql, SQL: select * from `password_reset_tokens` where `email` is null limit 1)
对应的迁移文件和控制器代码如下:
迁移文件
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::create('password_reset_tokens', function (Blueprint $table) { $table->string('phone_number')->primary(); $table->string('token'); $table->timestamp('created_at')->nullable(); }); } public function down(): void { Schema::dropIfExists('password_reset_tokens'); } };
控制器重置方法
public function resetPasswordConfirm(Request $request) { $request->validate([ 'token' => 'required', 'phone_number' => 'required|exists:users,phone_number', 'password' => 'required|min:5', ]); $response = Password::broker('users')->reset( [ 'phone_number' => $request->phone_number, 'password' => $request->password, 'password_confirmation' => $request->password_confirmation, 'token' => $request->token, ], function ($user, $password) { $user->forceFill([ 'password' => Hash::make($password), ])->save(); } ); if ($response == Password::PASSWORD_RESET) { return response()->json(['message' => '密码已成功重置']); } else { return response()->json(['error' => '无法重置密码,请检查输入的信息。']); } }
问题原因
Laravel默认的密码重置逻辑(包括Password Broker和TokenRepository)是基于email字段设计的,即使你传入phone_number,底层代码依然会默认使用email作为查询条件去查找令牌记录。
解决方案
1. 配置密码重置Broker使用手机号字段
修改config/auth.php文件,在passwords数组的users项中添加username配置,指定使用phone_number作为身份识别字段:
'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_reset_tokens', 'expire' => 60, 'username' => 'phone_number', // 新增此行 ], ],
2. 修改用户模型指定认证字段
在App\Models\User模型中,添加$username属性或重写getAuthIdentifierName方法,告诉框架使用phone_number作为用户认证的唯一标识:
// 方式一:直接设置username属性 protected $username = 'phone_number'; // 方式二:重写方法(更灵活) public function getAuthIdentifierName() { return 'phone_number'; }
3. 确保生成重置令牌时使用手机号
如果是自己实现发送重置令牌的逻辑,要确保传递phone_number而非email给sendResetLink方法:
$response = Password::broker('users')->sendResetLink( ['phone_number' => $request->phone_number] );
4. 自定义TokenRepository(可选,若上述配置不生效)
如果默认的TokenRepository依然强制使用email,可以创建自定义的令牌仓库类来替换:
创建自定义TokenRepository
<?php namespace App\Auth\Passwords; use Illuminate\Auth\Passwords\DatabaseTokenRepository; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; class PhoneNumberTokenRepository extends DatabaseTokenRepository { protected function getPayload(CanResetPasswordContract $user, $token) { return [ 'phone_number' => $user->getAuthIdentifier(), 'token' => $this->hasher->make($token), 'created_at' => now(), ]; } }
在AuthServiceProvider中注册自定义Broker
use App\Auth\Passwords\PhoneNumberTokenRepository; use Illuminate\Auth\Passwords\PasswordBroker; use Illuminate\Support\Facades\Auth; public function boot() { $this->registerPolicies(); Auth::broker()->extend('users', function ($app, $config) { $repository = new PhoneNumberTokenRepository( $app['db']->connection(), $app['hash'], $config['table'] ); return new PasswordBroker( $repository, $app['auth']->createUserProvider($config['provider']) ); }); }
完成以上步骤后,框架就会使用phone_number字段来查询和生成密码重置令牌,不会再出现email字段不存在的错误。
内容的提问来源于stack exchange,提问作者Erkhan Djakhanov
相关产品推荐
相关产品推荐

