You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel密码重置异常:所有请求仅修改首个用户密码求助

问题分析

你遇到的核心问题是密码重置时始终修改第一个用户的密码,主要原因有两点:

  1. PasswordReset模型未配置可填充字段:导致updateOrCreate方法无法正确写入/更新重置记录,系统始终读取旧的token关联的用户信息;
  2. 身份验证逻辑不严谨: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:25:25