服务器访问Laravel API的节流问题

时间:2019-07-11 20:52:18

标签: php laravel bandwidth-throttling

我有一个使用Laravel的API,该API是从另一个带有Guzzle的Laravel实例中调用的。

第二台服务器的IP地址正在触发API的限制。

我想将用户的域和IP地址从第二台服务器传递到API。我希望不要重新编码Throttle中间件。

我想知道以前是否有人遇到过这种问题,以及是否解决过。

API上的中间件组是这样设置的

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'api' => [
        'throttle:60,1',
        \Barryvdh\Cors\HandleCors::class,
        'bindings',
    ],
];

relevant throttle code

/**
 * Resolve request signature.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return string
 *
 * @throws \RuntimeException
 */
protected function resolveRequestSignature($request)
{
    if ($user = $request->user()) {
        return sha1($user->getAuthIdentifier());
    }
    if ($route = $request->route()) {
        return sha1($route->getDomain().'|'.$request->ip());
    }
    throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
}

4 个答案:

答案 0 :(得分:4)

您可以使用X_FORWARDED_FOR标头传递客户端的IP地址,这样就不会阻止第二台服务器的IP地址。

Route::get('/', function (Request $request) {

    $client = new \GuzzleHttp\Client();

    $request = $client->request('GET', '/api/example', [
        'headers' => ['X_FORWARDED_FOR' => $request->ip()]
    ]);

    $response = $request->getBody();

});

在主服务器上,您需要将第二台服务器作为可信代理(docs)添加到App\Http\Middleware\TrustProxies,以便从此标头中获取IP。

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array
     */
    protected $proxies = [
        '192.168.1.1', // <-- set the ip of the second server here 
    ];

    //...
}

现在,主服务器上对$request->ip()的每次调用都将具有原始客户端IP,而不是第二台服务器的IP。这也会影响节流。

答案 1 :(得分:0)

如果使用的版本> = 5.6,则开箱即用的解决方案是使用dynamic rate limit

  

动态速率限制

     

您可以根据已验证的用户模型的属性指定最大动态请求数。例如,如果您的用户模型包含rate_limit属性,则可以将该属性的名称传递给节流中间件,以便用于计算最大请求数:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

The relevant part of the code

/**
 * Resolve the number of attempts if the user is authenticated or not.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  int|string  $maxAttempts
 * @return int
 */
protected function resolveMaxAttempts($request, $maxAttempts)
{
    if (Str::contains($maxAttempts, '|')) {
        $maxAttempts = explode('|', $maxAttempts, 2)[$request->user() ? 1 : 0];
    }
    if (! is_numeric($maxAttempts) && $request->user()) {
        $maxAttempts = $request->user()->{$maxAttempts};
    }
    return (int) $maxAttempts;
}

因此,您可以在用户(代表第二台服务器)中添加一个rate_limit属性,并传递一个更大的数字

编辑:

如果您不希望对调用方进行身份验证,则可以轻松覆盖resolveMaxAttempts方法,以根据请求数据动态计算限制(可以使用任何参数,主机,ip等) ):

protected function resolveMaxAttempts($request, $maxAttempts)
{
    if (in_array(request->ip(), config('app.bypassThrottleMiddleware')) {
        return PHP_INT_MAX;
    }

    return parent::resolveMaxAttempts($request, $maxAttempts);
}

,然后在您的config/app.php中添加:

'bypassThrottleMiddleware' => ['0.0.0.0'],

答案 2 :(得分:-1)

在routes / api.php中(Laravel 5.6或更高版本)

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function (Request $request) {
        // $request->user()->getsSomethingAndIsRateLimited();
    });
});

答案 3 :(得分:-3)

if ($route = $request->route()) {
    return sha1($route->getDomain().'|'.$request->ip());