You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Laravel中如何限制OAuth登录尝试次数?——针对/v1/oauth/token接口及自定义方法的实现咨询

Great question—since you’ve already got regular login throttling sorted in your Laravel app, adapting that logic for the OAuth /v1/oauth/token endpoint is totally doable. Here are a few solid approaches to implement login attempt limits for OAuth flows:

Option 1: Add Throttle Middleware to the OAuth Token Route

The simplest way is to wrap the OAuth token endpoint with Laravel’s built-in throttle middleware. By default, Laravel Passport registers this route automatically, but you can override it to apply the middleware:

  1. Create a custom token controller that extends Passport’s default controller (to keep all existing OAuth logic intact):
namespace App\Http\Controllers\Auth;

use Laravel\Passport\Http\Controllers\TokenController;

class OAuthTokenController extends TokenController
{
    // No extra code needed here—we're just extending the default behavior
}
  1. Override the default /oauth/token route in your routes/api.php (or a service provider) to use your custom controller and apply the throttle middleware:
use App\Http\Controllers\Auth\OAuthTokenController;

Route::post('/oauth/token', [OAuthTokenController::class, 'issueToken'])
    ->middleware('throttle:5,1') // Allow 5 attempts per minute per IP/user
    ->name('passport.token');

Note: If you want to throttle by username instead of IP, you’ll need a custom middleware (see Option 3 for that).

Option 2: Customize the OAuth Grant to Include Throttling Logic

For more control (like only incrementing attempts when credentials are invalid), you can extend Passport’s PasswordGrant class to add throttling checks directly in the authentication flow:

  1. Create a custom grant class:
namespace App\Auth\Grants;

use Laravel\Passport\Grant\PasswordGrant;
use League\OAuth2\Server\RequestEvent;
use Psr\Http\Message\ServerRequestInterface;
use Illuminate\Support\Facades\RateLimiter;

class ThrottledPasswordGrant extends PasswordGrant
{
    protected function validateUser(ServerRequestInterface $request)
    {
        $username = $request->getParsedBody()['username'] ?? '';

        // Check if the user has exceeded the attempt limit
        if (RateLimiter::tooManyAttempts('oauth-login:'.$username, 5)) {
            $this->getEmitter()->emit(new RequestEvent(RequestEvent::AUTHORIZATION_FAILURE, $request));
            throw $this->invalidCredentialsException();
        }

        // Run Passport's default user validation
        $user = parent::validateUser($request);

        // Update attempt count based on validation result
        if (!$user) {
            RateLimiter::hit('oauth-login:'.$username); // Increment attempts on failure
        } else {
            RateLimiter::clear('oauth-login:'.$username); // Reset attempts on success
        }

        return $user;
    }
}
  1. Register the custom grant in your AuthServiceProvider:
use App\Auth\Grants\ThrottledPasswordGrant;
use Laravel\Passport\Passport;
use League\OAuth2\Server\AuthorizationServer;

public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    // Replace the default password grant with our throttled version
    app(AuthorizationServer::class)->enableGrantType(
        $this->makeThrottledPasswordGrant(), Passport::tokensExpireIn()
    );
}

protected function makeThrottledPasswordGrant()
{
    $grant = new ThrottledPasswordGrant(
        $this->app->make(\Laravel\Passport\Bridge\UserRepository::class),
        $this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class)
    );

    $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());

    return $grant;
}

Option 3: Build a Custom Throttling Middleware

If you want full flexibility (like logging attempts or customizing response messages), create a dedicated middleware to handle OAuth login throttling:

  1. Generate the middleware:
php artisan make:middleware OAuthLoginThrottle
  1. Add throttling logic to the middleware:
namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Response;

class OAuthLoginThrottle
{
    public function handle($request, Closure $next)
    {
        $username = $request->input('username');

        if (!$username) {
            return $next($request);
        }

        // Define your rate limit rules
        if (RateLimiter::tooManyAttempts('oauth-login:'.$username, 5)) {
            return response()->json([
                'error' => 'Too many login attempts. Please try again later.'
            ], Response::HTTP_TOO_MANY_REQUESTS);
        }

        $response = $next($request);

        // Increment attempts only if the response is an error
        if ($response->getStatusCode() === Response::HTTP_UNAUTHORIZED) {
            RateLimiter::hit('oauth-login:'.$username);
        }

        return $response;
    }
}
  1. Register the middleware in app/Http/Kernel.php:
protected $routeMiddleware = [
    // ...
    'oauth.throttle' => \App\Http\Middleware\OAuthLoginThrottle::class,
];
  1. Apply it to the OAuth token route:
Route::post('/oauth/token', [OAuthTokenController::class, 'issueToken'])
    ->middleware('oauth.throttle')
    ->name('passport.token');

All these approaches integrate seamlessly with Laravel’s existing rate-limiting system, so you can adjust the limits (e.g., throttle:10,1 for 10 attempts per minute) to fit your needs.

内容的提问来源于stack exchange,提问作者Monim Hossain

火山引擎 最新活动