Hi,
I’m building a project using slim 4 and everything is working fine (routes, controllers, database connections) and so I’ve started to implement a custom made authentication service in which the user is given a valid hash and should provide it in every request (GET, POST, PUT, DELETE).
Here is an example of the middleware that is implemented:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use App\Domain\User\Service\AuthenticationValidationService;
final class AuthenticationMiddleware implements MiddlewareInterface
{
private ResponseFactoryInterface $responseFactory;
private AuthenticationValidationService $service;
public function __construct(ResponseFactoryInterface $responseFactory, AuthenticationValidationService $service)
{
$this->responseFactory = $responseFactory;
$this->service = $service;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$data = (array)$request->getParsedBody();
$hash = $data['hash'];
$auth = $this->service->validateHash($hash);
if ($auth) {
//TODO: append userId associated with the hash to the request
return $handler->handle($request);
} else {
$response = $this->responseFactory->createResponse();
$response->getBody()->write('Unauthorized');
return $response->withStatus(401);
}
}
}
this is how its registered in my routes:
<?php
// Define app routes
use Slim\App;
use Slim\Routing\RouteCollectorProxy;
return function (App $app) {
// Redirect to Swagger documentation
$app->get('/', \App\Action\Home\HomeAction::class)->setName('home');
// API
$app->group(
'/api',
function (RouteCollectorProxy $app) {
$app->get('/user/{user_id}', \App\Action\User\UserReaderAction::class);
$app->post('/user', \App\Action\User\UserCreatorAction::class);
$app->put('/user/{user_id}', \App\Action\User\UserUpdaterAction::class);
$app->delete('/user/{user_id}', \App\Action\User\UserDeleterAction::class);
}
)->add(\App\Middleware\AuthenticationMiddleware::class);
$app->post('/api/user/login', \App\Action\User\UserLoginAction::class);
};
These are my middlewares:
<?php
use App\Middleware\ValidationExceptionMiddleware;
use Selective\BasePath\BasePathMiddleware;
use Slim\App;
use Slim\Middleware\ErrorMiddleware;
return function (App $app) {
$app->addBodyParsingMiddleware();
$app->add(ValidationExceptionMiddleware::class);
$app->addRoutingMiddleware();
$app->add(BasePathMiddleware::class);
$app->add(ErrorMiddleware::class);
};
Consider that the function validateHash()
returns true if the hash is valid and false otherwise. This function is working fine.
Everything works properly for POST and PUT.
But for GET and DELETE, $data = (array)$request->getParsedBody();
returns null
.
- example request that doesn’t work: …/api/user/1?hash=$2y$10$RK (GET)
- example request that works: …/api/user/1 (PUT) + JSON
{
“hash” : “$2y$10$RKojluryIrPwyMdvNbxqNONVi0iQDhtWndHp8td/hkL1VhXcJJ7fi”,
“last_name”: “admin”,
“first_name”: “admin”
}
What am I missing here? The main difference is that through GET/DELETE, parameters are passed inside the URL and POST/PUT are passed as json. Which is the appropriate way to read these request parameters regardless their method?
Furthermore, after validating the hash which is the better way to append the userId associated with the hash to the request before passing it to the handler?
Cheers!