Laravel密码重置异常:所有请求仅修改首个用户密码求助
问题分析
你遇到的核心问题是密码重置时始终修改第一个用户的密码,主要原因有两点:
PasswordReset模型未配置可填充字段:导致updateOrCreate方法无法正确写入/更新重置记录,系统始终读取旧的token关联的用户信息;- 身份验证逻辑不严谨:
resetPassword方法仅通过user_id查找用户,未验证该用户与当前重置token的关联,同时forgotPassword中获取用户的方式多余且易引发歧义。
修复步骤
1. 配置PasswordReset模型的可填充字段
打开PasswordReset.php模型,添加可填充字段,确保updateOrCreate能正确写入数据:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class PasswordReset extends Model { protected $fillable = ['email', 'token', 'created_at']; public $timestamps = false; // 因为手动设置了created_at,关闭自动时间戳 }
2. 优化forgotPassword方法
将get()改为first()(邮箱应唯一,无需返回集合),简化用户存在性判断:
public function forgotPassword(Request $request) { try { // 用first()获取单个用户,而非集合 $user = User::where('email', $request->email)->first(); if ($user) { $token = Str::random(40); $domain = URL::to('/'); $url = $domain.'/reset-Password?token='.$token; $data = [ 'url' => $url, 'email' => $request->email, 'title' => "Password Reset", 'body' => "Please click the link below to reset your password" ]; Mail::send('forgetPasswordMail', ['data' => $data], function ($message) use ($data) { $message->to($data['email'])->subject($data['title']); }); // 无需手动格式化时间,Carbon实例可直接存入 PasswordReset::updateOrCreate( ['email' => $request->email], [ 'token' => $token, 'created_at' => Carbon::now() ] ); return response()->json(['success' => true, 'msg' => 'Password Reset Sent']); } else { return response()->json(['success' => false, 'msg' => 'User not Found']); } } catch(\Exception $e) { return response()->json(['success' => false, 'msg' => $e->getMessage()]); } }
3. 完善resetPassword方法,增加身份验证
添加token与用户的关联验证,确保只有token对应的用户才能修改密码,同时改进返回方式:
public function resetPassword(Request $request) { $request->validate([ 'password' => 'required|string|min:6|confirmed', 'token' => 'required|string' // 新增token验证 ]); // 先通过token找到重置记录 $resetData = PasswordReset::where('token', $request->token)->first(); if (!$resetData) { return "<h1>Error: Invalid or expired token</h1>"; } // 通过重置记录的邮箱找到用户 $user = User::where('email', $resetData->email)->first(); if ($user) { $user->password = Hash::make($request->password); $user->save(); PasswordReset::where('email', $user->email)->delete(); // 建议重定向到登录页,而非返回HTML字符串 return redirect()->route('login')->with('success', 'Password reset successfully'); } else { return "<h1>Error: User not found</h1>"; } }
4. 修改重置密码视图,替换user_id为token
移除隐藏的user_id字段,改为传递token,避免依赖前端传递用户ID:
@if($errors->any()) <ul> @foreach($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> @endif <center> <form method="POST" action="/reset-Password"> @csrf <!-- 传递token而非user_id --> <input type="hidden" name="token" value="{{ request()->token }}"> <input type="password" name="password" placeholder="New Password"> <br> <br> <input type="password" name="password_confirmation" placeholder="Confirm Password"> <br> <br> <input type="submit"> </form> </center>
内容的提问来源于stack exchange,提问作者Black Fecta
相关产品推荐
相关产品推荐

