Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do a redirect from a Slim 4 middleware?

I've been testing the new Slim 4 framework and redirects work fine for me in normal classes, but I cannot seem to get them working in middleware, where a response is dynamically generated (apparently?) by the Request Handler. When I try to redirect with a Location header, it simply fails to redirect, and my route continues to the original location.

Here’s a basic version of my authentication middleware for testing:

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class AuthMiddleware extends Middleware {

    public function __invoke(Request $request, RequestHandler $handler): Response {
        $response = $handler->handle($request);
        $loggedInTest = false;
        if ($loggedInTest) {
            echo "User authorized.";
            return $response;
        } else {
            echo "User NOT authorized.";
            return $response->withHeader('Location', '/users/login')->withStatus(302);
        }
    }
}

Has anybody got this to work? And if so, how did you accomplish it? Thanks in advance.

like image 232
ConleeC Avatar asked Oct 18 '25 15:10

ConleeC


2 Answers

I think I see the problem with this code.

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class AuthMiddleware extends Middleware {

    public function __invoke(Request $request, RequestHandler $handler): Response {
        $response = $handler->handle($request);
        $loggedInTest = false;
        if ($loggedInTest) {
            echo "User authorized.";
            return $response;
        } else {
            echo "User NOT authorized.";
            return $response->withHeader('Location', '/users/login')->withStatus(302);
        }
    }
}

When you call $handler->handle($request), that processes the request normally and calls whatever closure is supposed to handle the route. The response hasn't been completed yet, you can still append stuff to it, but the headers are already set, so you can't do a redirect, because the headers are done.

Maybe try this:

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;

class AuthMiddleware extends Middleware {

    public function __invoke(Request $request, RequestHandler $handler): ResponseInterface {            
        $loggedInTest = false;
        if ($loggedInTest) {
            $response = $handler->handle($request);
            echo "User authorized.";
            return $response;
        } else {
            $response = new Response();
            // echo "User NOT authorized.";
            return $response->withHeader('Location', '/users/login')->withStatus(302);
        }
    }
}

If the login test fails, we never call $handler->handle(), so the normal response doesn't get generated. Meanwhile, we create a new response.

Note that the ResponseInterface and Response can't both be called Response in the same file, so I had to remove that alias, and just call the ResponseInterface by its true name. You could give it a different alias, but I think that would only create more confusion.

Also, I commented out the echo before the redirect. I think this echo will force headers to be sent automatically, which will break the redirect. Unless Slim 4 is doing output buffering, in which case you're still not going to see it, because the redirect will immediately send you to a different page. Anyway, I commented it out to give the code the best chance of working but left it in place for reference.

Anyway, I think if you make that little change, everything will work. Of course, this post is almost a year old, so you've probably solved this on your own, switched to F3, or abandoned the project by now. But hopefully, this will be helpful to someone else. That's the whole point of StackOverflow, right?

like image 97
eimajenthat Avatar answered Oct 20 '25 05:10

eimajenthat


eimajenthat is right, except that you cannot create an instance of interface.

Try this instead:

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;

class AuthMiddleware extends Middleware {

public function __invoke(Request $request, RequestHandler $handler): Response {            
    global $app; // Assuming $app is your global object

    $loggedInTest = false;
    if ($loggedInTest) {
        $response = $handler->handle($request);
        echo "User authorized.";
        return $response;
    } else {
        $response = $app->getResponseFactory()->createResponse();
        // echo "User NOT authorized.";
        return $response->withHeader('Location', '/users/login')->withStatus(302);
    }
}

}

like image 38
Anastas Dolushanov Avatar answered Oct 20 '25 04:10

Anastas Dolushanov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!