Skip to content

Instantly share code, notes, and snippets.

@demisang
Last active November 28, 2017 16:04
Show Gist options
  • Save demisang/17a70a4b6e5bd6dca333a1a42b375b1b to your computer and use it in GitHub Desktop.
Save demisang/17a70a4b6e5bd6dca333a1a42b375b1b to your computer and use it in GitHub Desktop.
<?php
namespace common\components\rateLimiter;
use Yii;
use yii\base\BaseObject;
use yii\filters\RateLimitInterface;
/**
* Auth rate limiter
*
* Max 60 login requests allowed per minute
*
* mongodb collection schema example:
* {
* userIp: "192.168.83.1",
* timestamp: 1511884342
* }
*/
class AuthRateLimiter extends BaseObject implements RateLimitInterface
{
public $mongoDbComponent = 'mongodb';
public $mongoCollection = 'loginRequests';
protected $maxRequestsPerWindowSize = 30;
protected $windowSize = 60;
public function __construct($maxRequests = 30, $windowSize = 60, array $config = [])
{
$this->maxRequestsPerWindowSize = $maxRequests;
$this->windowSize = $windowSize;
parent::__construct($config);
}
/**
* Returns the maximum number of allowed requests and the window size.
*
* @param \yii\web\Request $request the current request
* @param \yii\base\Action $action the action to be executed
*
* @return array an array of two elements. The first element is the maximum number of allowed requests,
* and the second element is the size of the window in seconds.
*/
public function getRateLimit($request, $action)
{
// 30 times per minute
return [$this->maxRequestsPerWindowSize, $this->windowSize];
}
/**
* Loads the number of allowed requests and the corresponding timestamp from a persistent storage.
*
* @param \yii\web\Request $request the current request
* @param \yii\base\Action $action the action to be executed
*
* @return array an array of two elements. The first element is the number of allowed requests,
* and the second element is the corresponding UNIX timestamp.
*/
public function loadAllowance($request, $action)
{
$query = new \yii\mongodb\Query();
$query->from($this->mongoCollection)
->where([
'and',
['userIp' => $request->userIP], // @todo use ip2long() instead string?
['>=', 'timestamp', time() - $this->windowSize],
]);
$count = $query->count('*', $this->getMongo());
return [$this->maxRequestsPerWindowSize - $count, time()];
}
/**
* Saves the number of allowed requests and the corresponding timestamp to a persistent storage.
*
* @param \yii\web\Request $request the current request
* @param \yii\base\Action $action the action to be executed
* @param int $allowance the number of allowed requests remaining.
* @param int $timestamp the current timestamp.
*/
public function saveAllowance($request, $action, $allowance, $timestamp)
{
$this->getMongo()->createCommand()->insert($this->mongoCollection, [
'userIp' => $request->userIP, // @todo use long2ip() instead string?
'timestamp' => $timestamp,
]);
}
/**
* Get MongoDB connection
*
* @return mixed|\yii\mongodb\Connection
*/
private function getMongo()
{
$name = $this->mongoDbComponent;
return Yii::$app->$name;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment