如何在Laravel密码Broker中生成短有效期的4位数字重置令牌
实现Laravel自定义4位数字密码重置令牌
步骤1:创建自定义Password Broker类
在app/Providers/Auth目录下新建ApiUserPasswordBroker.php(目录不存在则手动创建),重写令牌生成与验证逻辑:
<?php namespace App\Providers\Auth; use Illuminate\Auth\Passwords\PasswordBroker as BasePasswordBroker; use Illuminate\Support\Str; class ApiUserPasswordBroker extends BasePasswordBroker { /** * 生成4位数字重置令牌并保存 * * @param \Illuminate\Contracts\Auth\CanResetPassword $user * @return string */ public function createToken($user) { $email = $user->getEmailForPasswordReset(); // 清除用户已有的旧令牌 $this->tokens->deleteExisting($user); // 生成唯一的4位数字令牌 do { $token = Str::randomNumeric(4); } while ($this->tokens->exists($email, $token)); // 存储令牌到数据库 $this->tokens->create([ 'email' => $email, 'token' => $token, 'created_at' => now(), ]); return $token; } /** * 验证令牌有效性 * * @param \Illuminate\Contracts\Auth\CanResetPassword $user * @param string $token * @return bool */ public function validateToken($user, $token) { $record = $this->tokens->get($user->getEmailForPasswordReset(), $token); return $record && !$this->tokenExpired($record); } }
步骤2:替换默认的密码Broker
在app/Providers/AuthServiceProvider.php的boot方法中注册自定义Broker,替换api_users对应的默认实现:
<?php namespace App\Providers; use App\Providers\Auth\ApiUserPasswordBroker; use Illuminate\Auth\Passwords\PasswordBrokerManager; use Illuminate\Support\ServiceProvider; class AuthServiceProvider extends ServiceProvider { public function boot() { $this->registerPolicies(); // 替换api_users的密码broker实例 $this->app->extend(PasswordBrokerManager::class, function ($manager) { $manager->extend('api_users', function ($app) { $tokens = $app['auth.password.tokens']; $users = $app['auth']->createUserProvider('api_users'); $view = $app['config']['auth.passwords.api_users.email']; return new ApiUserPasswordBroker( $tokens, $users, $app['mailer'], $view ); }); return $manager; }); } }
步骤3:调整令牌表结构
默认password_reset_tokens表的token字段是为哈希值设计的长字段,现在修改为适合4位数字的长度:
- 若未创建表,修改迁移文件:
Schema::create('password_reset_tokens', function (Blueprint $table) { $table->string('email')->primary(); $table->string('token', 4); // 限制长度为4 $table->timestamp('created_at')->nullable(); });
- 若已存在表,创建新迁移修改字段:
Schema::table('password_reset_tokens', function (Blueprint $table) { $table->string('token', 4)->change(); });
步骤4:调整重置密码的验证逻辑
在重置密码的处理方法中,添加4位数字令牌的校验规则:
public function resetPassword(Request $request) { $validator = Validator::make($request->all(), [ 'email' => 'required|email|exists:api_users,email', 'token' => 'required|digits:4', // 强制验证4位数字 'password' => 'required|confirmed|min:8', ]); if ($validator->fails()) { throw new ValidationException($validator); } $broker = Password::broker('api_users'); $response = $broker->reset( $request->only('email', 'token', 'password', 'password_confirmation'), function ($user, $password) { $user->password = Hash::make($password); $user->save(); } ); return $response === Password::PASSWORD_RESET ? response()->json(['msg' => '密码重置成功'], 200) : response()->json(['msg' => '无效的令牌或邮箱'], 400); }
注意事项
- 4位数字令牌的安全性依赖于15分钟有效期和120秒限流配置,若需更高安全性可改为6位数字。
- 生成令牌时必须校验唯一性,避免不同用户拿到重复令牌导致逻辑冲突。
- 此处直接存储明文令牌,结合短有效期和限流规则,安全性可控,无需哈希存储。
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas
相关产品推荐
相关产品推荐

