Chrisbjr\ApiGuard\Http\Middleware\ApiGuard::handle PHP Method

handle() public method

Handle an incoming request.
public handle ( Illuminate\Http\Request $request, Closure $next, null $serializedApiMethods = null ) : mixed
$request Illuminate\Http\Request
$next Closure
$serializedApiMethods null
return mixed
    public function handle(Request $request, Closure $next, $serializedApiMethods = null)
    {
        // Unserialize parameters
        if (!is_null($serializedApiMethods)) {
            $this->apiMethods = unserialize($serializedApiMethods);
        }
        // Let's instantiate the response class first
        $response = ApiResponseBuilder::build();
        // Let's get the method
        $method = $this->getRouteMethod();
        if (empty($method)) {
            // There is no method
            return $response->errorMethodNotAllowed();
        }
        // We should check if key authentication is enabled for this method
        $keyAuthentication = true;
        if (isset($this->apiMethods[$method]['keyAuthentication']) && $this->apiMethods[$method]['keyAuthentication'] === false) {
            $keyAuthentication = false;
        }
        if ($keyAuthentication === true) {
            $key = $request->header(config('apiguard.keyName', 'X-Authorization'));
            if (empty($key)) {
                // Try getting the key from elsewhere
                $key = $request->get(config('apiguard.keyName', 'X-Authorization'));
            }
            if (empty($key)) {
                // It's still empty!
                return $response->errorUnauthorized();
            }
            $apiKeyModel = App::make(config('apiguard.models.apiKey', 'Chrisbjr\\ApiGuard\\Models\\ApiKey'));
            if (!$apiKeyModel instanceof ApiKeyRepository) {
                Log::error('[ApiGuard] Your ApiKey model should be an instance of ApiKeyRepository.');
                throw new Exception("You ApiKey model should be an instance of ApiKeyRepository.");
            }
            $this->apiKey = $apiKeyModel->getByKey($key, config('apiguard.rememberApiKeyDuration', 0));
            if (empty($this->apiKey)) {
                return $response->errorUnauthorized();
            }
            // Authenticate the user of this API key
            ApiGuardAuth::authenticate($this->apiKey);
            // API key exists
            // Check level of API
            if (!empty($this->apiMethods[$method]['level'])) {
                if ($this->apiKey->level < $this->apiMethods[$method]['level']) {
                    return $response->errorForbidden();
                }
            }
        }
        $apiLog = App::make(config('apiguard.models.apiLog', 'Chrisbjr\\ApiGuard\\Models\\ApiLog'));
        if (!$apiLog instanceof ApiLogRepository) {
            Log::error('[ApiGuard] Your ApiLog model should be an instance of ApiLogRepository.');
            throw new Exception("You ApiLog model should be an instance of ApiLogRepository.");
        }
        // Then check the limits of this method
        if (!empty($this->apiMethods[$method]['limits'])) {
            if (config('apiguard.logging', true) === false) {
                Log::warning("[ApiGuard] You specified a limit in the {$method} method but API logging needs to be enabled in the configuration for this to work.");
            }
            $limits = $this->apiMethods[$method]['limits'];
            // We get key level limits first
            if ($this->apiKey != null && !empty($limits['key'])) {
                $keyLimit = !empty($limits['key']['limit']) ? $limits['key']['limit'] : 0;
                if ($keyLimit == 0 || is_integer($keyLimit) == false) {
                    Log::warning("[ApiGuard] You defined a key limit to the " . Route::currentRouteAction() . " route but you did not set a valid number for the limit variable.");
                } else {
                    if (!$this->apiKey->ignore_limits) {
                        // This means the apikey is not ignoring the limits
                        $keyIncrement = !empty($limits['key']['increment']) ? $limits['key']['increment'] : config('apiguard.keyLimitIncrement', '1 hour');
                        $keyIncrementTime = strtotime('-' . $keyIncrement);
                        if ($keyIncrementTime == false) {
                            Log::warning("[ApiGuard] You have specified an invalid key increment time. This value can be any value accepted by PHP's strtotime() method");
                        } else {
                            // Count the number of requests for this method using this api key
                            $apiLogCount = $apiLog->countApiKeyRequests($this->apiKey->id, Route::currentRouteAction(), $request->getMethod(), $keyIncrementTime);
                            if ($apiLogCount >= $keyLimit) {
                                Log::warning("[ApiGuard] The API key ID#{$this->apiKey->id} has reached the limit of {$keyLimit} in the following route: " . Route::currentRouteAction());
                                return $response->setStatusCode(429)->withError('You have reached the limit for using this API.', 'GEN-TOO-MANY-REQUESTS');
                            }
                        }
                    }
                }
            }
            // Then the overall method limits
            if (!empty($limits['method'])) {
                $methodLimit = !empty($limits['method']['limit']) ? $limits['method']['limit'] : 0;
                if ($methodLimit == 0 || is_integer($methodLimit) == false) {
                    Log::warning("[ApiGuard] You defined a method limit to the " . Route::currentRouteAction() . " route but you did not set a valid number for the limit variable.");
                } else {
                    if ($this->apiKey != null && $this->apiKey->ignore_limits == true) {
                        // then we skip this
                    } else {
                        $methodIncrement = !empty($limits['method']['increment']) ? $limits['method']['increment'] : config('apiguard.keyLimitIncrement', '1 hour');
                        $methodIncrementTime = strtotime('-' . $methodIncrement);
                        if ($methodIncrementTime == false) {
                            Log::warning("[ApiGuard] You have specified an invalid method increment time. This value can be any value accepted by PHP's strtotime() method");
                        } else {
                            // Count the number of requests for this method
                            $apiLogCount = $apiLog->countMethodRequests(Route::currentRouteAction(), $request->getMethod(), $methodIncrementTime);
                            if ($apiLogCount >= $methodLimit) {
                                Log::warning("[ApiGuard] The API has reached the method limit of {$methodLimit} in the following route: " . Route::currentRouteAction());
                                return $response->setStatusCode(429)->withError('The limit for using this API method has been reached', 'GEN-TOO-MANY-REQUESTS');
                            }
                        }
                    }
                }
            }
        }
        // End of cheking limits
        if (config('apiguard.logging', true)) {
            // Default to log requests from this action
            $logged = true;
            if (isset($this->apiMethods[$method]['logged']) && $this->apiMethods[$method]['logged'] === false) {
                $logged = false;
            }
            if ($logged) {
                // Log this API request
                $this->apiLog = App::make(config('apiguard.models.apiLog', 'Chrisbjr\\ApiGuard\\Models\\ApiLog'));
                if (isset($this->apiKey)) {
                    $this->apiLog->api_key_id = $this->apiKey->id;
                }
                $this->apiLog->create(['api_key_id' => isset($this->apiKey) ? $this->apiKey->id : null, 'route' => Route::currentRouteAction(), 'method' => $request->getMethod(), 'params' => http_build_query(Input::all()), 'ip_address' => $request->getClientIp()]);
            }
        }
        return $next($request);
    }