Проблема с дросселем при обращении к серверу Laravel API - PullRequest
4 голосов
/ 11 июля 2019

У меня есть API, использующий Laravel, который вызывается из другого экземпляра Laravel с помощью Guzzle.

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',
    ],
];

соответствующий код газа

/**
 * 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.');
}

Ответы [ 3 ]

4 голосов
/ 16 июля 2019

IP-адрес клиента можно передать с заголовком X_FORWARDED_FOR, чтобы 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();

});

На главном сервере необходимо добавить второй сервер.в качестве доверенного прокси ( документы ) на 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-адреса второго сервера.Это также повлияет на регулирование.

0 голосов
/ 16 июля 2019

Готовым решением, если вы используете версию> = 5.6, является использование динамического ограничения скорости .

Динамическое ограничение скорости

Вы можете указать максимум динамического запроса на основе атрибута модели аутентифицированного пользователя. Например, если ваша модель пользователя содержит атрибут rate_limit, вы можете передать имя атрибута промежуточному программному обеспечению дросселя, чтобы оно использовалось для расчета максимального числа запросов:

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

Соответствующая часть кода

/**
 * 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 в пользователя (представляющее второй сервер) и передать большее число

EDIT:

Если вы не хотите, чтобы вызывающая сторона аутентифицировалась, вы можете легко перезаписать метод 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'],
0 голосов
/ 12 июля 2019
if ($route = $request->route()) {
    return sha1($route->getDomain().'|'.$request->ip());
...