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:
- 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 }
- Override the default
/oauth/tokenroute in yourroutes/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:
- 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; } }
- 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:
- Generate the middleware:
php artisan make:middleware OAuthLoginThrottle
- 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; } }
- Register the middleware in
app/Http/Kernel.php:
protected $routeMiddleware = [ // ... 'oauth.throttle' => \App\Http\Middleware\OAuthLoginThrottle::class, ];
- 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




