Laravel 5.5密码重置:能否将password_resets表删除改为更新操作?
我在Laravel 5.5中进行密码重置时遇到权限问题:提交邮箱后,系统执行DELETE操作时提示权限不足,错误信息如下:
SQLSTATE[42000]: Syntax error or access violation: 1142 DELETE command denied to user 'root'@'localhost' for table 'password_resets' (SQL: delete from
password_resetswhere
我想知道能否将password_resets表的删除操作改为更新操作?如果可以,需要修改哪些文件?
我曾尝试在自定义的ForgotPasswordController.php的index方法中先执行该邮箱的删除查询,再调用SendsPasswordResetEmails.php的相关逻辑,但错误依然存在。
我的User模型代码如下:
<?php namespace App; use Laravel\Passport\HasApiTokens; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Contracts\Auth\CanResetPassword; use Illuminate\Database\Eloquent\SoftDeletes; class User extends Authenticatable { use SoftDeletes, HasApiTokens, Notifiable; protected $table = 'tbl_users'; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', 'user_type', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'remember_token', ]; }
当然可以把删除操作改成更新!Laravel的密码重置逻辑是可扩展的,核心就是替换默认的令牌存储逻辑,把“删除旧记录再新增”改成“更新旧记录(如果存在)”。下面是具体步骤:
1. 自定义密码重置令牌Repository
Laravel默认用Illuminate\Auth\Passwords\DatabaseTokenRepository来处理令牌的存储,我们需要创建一个自定义类覆盖它的create方法:
在app/Auth/Passwords/目录下创建CustomDatabaseTokenRepository.php(如果目录不存在就新建),代码如下:
<?php namespace App\Auth\Passwords; use Illuminate\Auth\Passwords\DatabaseTokenRepository as BaseRepository; use Illuminate\Support\Carbon; class CustomDatabaseTokenRepository extends BaseRepository { /** * 创建新的密码重置令牌(替换删除为更新) * * @param \Illuminate\Contracts\Auth\CanResetPassword $user * @return string */ public function create($user) { $email = $user->getEmailForPasswordReset(); // 先检查该邮箱是否已有重置记录 $existingRecord = $this->getTable()->where('email', $email)->first(); if ($existingRecord) { // 如果存在,直接更新令牌和过期时间,不用删除 $newToken = $this->createNewToken(); $existingRecord->update([ 'token' => $this->hasher->make($newToken), 'created_at' => Carbon::now() ]); return $newToken; } // 没有旧记录的话,还是走默认的新增逻辑 return parent::create($user); } }
2. 替换默认的Repository绑定
接下来要告诉Laravel用我们自定义的Repository,而不是默认的。打开app/Providers/AuthServiceProvider.php,在register方法里添加绑定:
use App\Auth\Passwords\CustomDatabaseTokenRepository; use Illuminate\Auth\Passwords\TokenRepositoryInterface; public function register() { parent::register(); // 绑定自定义的令牌Repository到接口 $this->app->bind( TokenRepositoryInterface::class, CustomDatabaseTokenRepository::class ); }
3. 验证表结构(可选)
确认你的password_resets表有email、token、created_at这三个字段,一般Laravel的默认迁移已经包含了,不需要额外修改。如果没建表的话,执行默认的密码重置迁移:
php artisan migrate --path=vendor/laravel/framework/src/Illuminate/Auth/Console/migrations
为什么你之前的尝试没生效?
你之前在ForgotPasswordController里手动删除,但Laravel默认的create方法内部还是会执行删除旧记录的操作(就在DatabaseTokenRepository的create方法开头),所以必须覆盖这个核心方法才能彻底替换掉删除逻辑。
备选方案:直接添加DELETE权限(如果允许的话)
如果服务器允许修改数据库权限,也可以直接给root@localhost用户添加password_resets表的DELETE权限,执行这条SQL:
GRANT DELETE ON your_database_name.password_resets TO 'root'@'localhost'; FLUSH PRIVILEGES;
把your_database_name换成你的实际数据库名就行。不过如果权限无法修改,前面的自定义Repository方案就是更稳妥的长期解决办法。
内容的提问来源于stack exchange,提问作者Mageto Denis

