Reputation: 7318
The goal is to redirect user to the login page from a middleware. The middleware is called from a slim route group with this line:
$this->get( '/profile', ProfileController::class . ':index' )->add( new RequireLogin() );
And here is the middleware
<?php
namespace Rib\Src\MiddleWares;
use Rib\Src\Services\FlashMessages;
use Slim\Http\Request;
use Slim\Http\Response;
class RequireLogin
{
/**
* Example middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke( $request, $response, $next )
{
if ( ! isset( $_SESSION[ 'id' ] ) ) {
FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
header( 'Location: /user/login' ); # THIS LINE
exit; # AND THIS ONE
}
$response = $next( $request, $response );
return $response;
}
}
My goal is that when middleware detects that the user is not currently logged in, then redirect user to login page. You can see that my current way is BAD: I use a redirect followed by an exit.
How could I replace these 2 lines with the proper "slim" way ?
Upvotes: 0
Views: 2216
Reputation: 1579
Response
has a handy method withRedirect()
, you can use it like this:
<?php
if (!isset($_SESSION[ 'id' ])) {
FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
$url = '/user/login';
return $response->withRedirect($url);
} else {
return $next($request, $response);
}
However there's still one problem: you're hardcoding URL where you want non-authenticated users to redirected to. Consider getting that URL via it's name (that you may give when declaring route):
<?php
// Add unique name to the route so you can
// refer to it later in the code (this is what we're going to do now)
$app->get('/user/login', YourController::class)->setName('userLoginPage');
Now you can refer to that route via name, not the URL itself in the middleware. For that you need to inject Slim Router object:
<?php
namespace Rib\Src\MiddleWares;
use Rib\Src\Services\FlashMessages;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Router;
class RequireLogin
{
/**
* Object constructor
*
* Inject Slim Router here, so you can access route names.
*
* @param Router $router
*/
public function __construct(Router $router)
{
$this->router = $router;
}
/**
* Example middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke( $request, $response, $next )
{
if ( ! isset( $_SESSION[ 'id' ] ) ) {
FlashMessages::flashIt( 'message', "The page you tried to access requires an active session. Please log back in." );
// Get url by name: this is more flexible than hardcoding URL
$url = $this->router->pathFor('userLoginPage') . ' #forbidden';
return $response->withRedirect($url);
} else {
return $next( $request, $response );
}
}
}
The benefit here is that when you change actual URL for the user login page, you don't have to change it in the middleware, since it's accessed via $router->pathFor()
method.
I'd say this is very Slim, nice way. )
Upvotes: 3