Is there a way for a middleware to immediately return a response to the client without going through the routes?
I’m thinking of using middleware to check for IP and if its not in the range of IPs I accept, i want to return a response saying “i don’t know you” or the like.
I’m currently using the withAttribute and then checking the attribute i set there, but i want to add the middleware to a group of routes and adding a check in each route is really just troublesome.
Any thoughts? how can i just reject/respond immediately/skip routes from the middleware itself?
I think this is what you are looking for, simple if statement in middleware? (using slim v4)
//....
class ContentLengthMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (SOMECONDITION) {
// usual flow, go deeper in Middlewares stack
return $handler->handle($request); // will return usual response
}
$response = new Response(); // your completely custom Response, ignoring usual middleware stack
// do your stuff
return $response;
}
}
I want the code inside the GET /lala to completely be ignored if the IP does not match any of my accepted ones in $checkIpMiddleware and immediately return a response to the client.
I’ve been able to do that by doing withAttribute in the middleware and then getAttribute in the route, like:
$ipAllowed = $request->getAttribute('ip_allowed');
if (!isset($ipAllowed)) {
return $response;
}
but if i have a group, for example:
$app->group('/admin', function(...){
$group->('/login', function (Request $request, Response $response, $args) {
$ipAllowed = $request->getAttribute('ip_allowed');
if (!isset($ipAllowed)) {
return $response;
}
// code
});
$group->('/client', ...{
//same check
$ipAllowed = $request->getAttribute('ip_allowed');
if (!isset($ipAllowed)) {
return $response;
}
});
$group->(....
// more
})
That would mean copy pasting alot of the ip_allowed condition check into the start of all of those right?
Returning a Response in the middleware ends the middleware chain, stoping whatever middleware you have next (dependending on the stage of the middleware it can end the chain before routing, for example).
What make the chain running one middleware after another is calling return $handler->handle($request);
That error seems related to the ‘nope’ Response you are creating. I’m assuming here you are trying to create a new response from the response interface, which would be incorrect.
For example, when using Slim-Psr7 you can do something like this:
$responseFactory = new \Slim\Psr7\ResponseFactory;
I think what you said would give him a Type error instead. Instantiation errors happens when “new” is called. Maybe “new” is calling the Response Interface instead of a Response Object… ?!
The PSR-15 signature of the function seems correct.
//put this in the middleware closure declaration so i can use $app inside it
...
use ($app)
...
//then use that to get the factory to create the response
$response = $app->getResponseFactory()->createResponse();
However, I got the above from the custom error handlers and render part and actually scarpped that and now changed my code to throw errors instead with a custom exception so i can pass the status code as well:
class ExceptionWithStatus extends \Exception {
private $statusCode;
public function __construct($message, $statusCode) {
$this->statusCode = $statusCode;
parent::__construct($message);
}
public function getStatusCode() {
return $this->statusCode;
}
}
$checkCrmIPMiddleware = function (Request $request, RequestHandler $handler) {
$serverParams = $request->getServerParams();
$ipList = [
'xxx.xx.xxx.xxx'
];
if (in_array($serverParams['REMOTE_ADDR'], $ipList)) {
$response = $handler->handle($request);
return $response;
} else {
throw new ExceptionWithStatus('Nope', 401);
}
};
the errors will be caught by the custom error response closure (from the docs) and i can append my custom status code: