Last active
November 28, 2017 16:04
-
-
Save demisang/17a70a4b6e5bd6dca333a1a42b375b1b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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