Laravel 5.6 Passport OAuth登录失败次数限制与用户锁定实现咨询
嘿,作为Laravel和Passport新手,能搭好这套OAuth系统已经很厉害了!关于登录失败后锁定用户的需求,Laravel本身并没有直接内置针对Passport的专属功能,但有几个靠谱的方案能搞定——要么用成熟的第三方工具,要么自己动手实现,我给你拆解得明明白白:
有几个不错的包可以简化开发,比如spatie/laravel-failed-login-lockout,它专门处理登录失败锁定逻辑,不过默认是针对Laravel原生登录的。如果想用它适配Passport,你需要额外监听Passport的认证失败事件,稍微有点折腾。对于新手来说,其实自己动手实现反而能更清楚Passport的运行逻辑,也更灵活。
我给你梳理一套最直接的实现方案,基于自定义Passport的密码授权逻辑来做:
1. 给用户表添加必要字段
首先需要记录失败次数和锁定时间,生成一个迁移文件:
php artisan make:migration add_failed_login_fields_to_users_table --table=users
打开生成的迁移文件,添加两个字段:
public function up() { Schema::table('users', function (Blueprint $table) { $table->integer('failed_login_attempts')->default(0); $table->timestamp('locked_at')->nullable(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn(['failed_login_attempts', 'locked_at']); }); }
运行迁移生效:
php artisan migrate
2. 配置锁定规则
在项目根目录新建config/login-lockout.php,存放锁定的参数(方便后续调整):
return [ 'max_attempts' => 5, // 允许的最大失败登录次数 'lockout_minutes' => 15, // 锁定时长(分钟) ];
3. 自定义Passport的密码授权逻辑
Passport的密码登录逻辑是由PasswordGrant类处理的,我们需要重写它来加入锁定判断:
在app/Auth/Grants目录下创建PasswordGrant.php(目录不存在就新建):
<?php namespace App\Auth\Grants; use League\OAuth2\Server\Exception\OAuthServerException; use Laravel\Passport\Bridge\User; use Laravel\Passport\PasswordGrant as BaseGrant; class PasswordGrant extends BaseGrant { // 验证用户是否被锁定 protected function validateUser($request) { $user = parent::validateUser($request); // 检查用户是否处于锁定状态 if ($user->locked_at && now()->lessThan($user->locked_at->addMinutes(config('login-lockout.lockout_minutes')))) { throw OAuthServerException::accessDenied('您的账户因多次登录失败已被锁定,请15分钟后再尝试'); } return $user; } // 验证密码并更新失败次数/锁定状态 protected function validateCredentials(User $user, $password) { $isValid = parent::validateCredentials($user, $password); $userModel = $user->getAuthModel(); if (!$isValid) { // 失败次数+1 $userModel->increment('failed_login_attempts'); // 达到最大次数,锁定账户 if ($userModel->failed_login_attempts >= config('login-lockout.max_attempts')) { $userModel->update(['locked_at' => now()]); } return false; } // 登录成功,重置失败次数和锁定状态 $userModel->update([ 'failed_login_attempts' => 0, 'locked_at' => null, ]); return true; } }
4. 替换Passport默认的授权逻辑
打开app/Providers/AuthServiceProvider.php,在boot方法里替换默认的PasswordGrant:
use App\Auth\Grants\PasswordGrant; use Laravel\Passport\Passport; use League\OAuth2\Server\AuthorizationServer; public function boot() { $this->registerPolicies(); Passport::routes(); // 替换自定义的密码授权逻辑 $this->app->extend(AuthorizationServer::class, function ($server, $app) { $server->enableGrantType( $this->makePasswordGrant(), Passport::tokensExpireIn() ); return $server; }); } // 创建自定义的PasswordGrant实例 protected function makePasswordGrant() { $grant = new PasswordGrant( $this->app->make(\Laravel\Passport\Bridge\UserRepository::class), $this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class) ); $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn()); return $grant; }
5. 可选:添加手动解锁功能
如果需要管理员手动解锁用户,可以在User模型里加一个方法:
public function unlock() { $this->update([ 'failed_login_attempts' => 0, 'locked_at' => null, ]); }
之后管理员就能通过$user->unlock()来解锁指定用户了。
这样一套流程下来,你的Passport OAuth系统就拥有登录失败锁定的功能啦!测试的时候可以故意输错密码5次,看看是否会被锁定,登录成功后是否会重置状态。
内容的提问来源于stack exchange,提问作者Ricky

