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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:06:46