4

I have a project with CodeIgniter 4.

I have a before filter:

public function before(RequestInterface $request){

    $auth = $request->getHeader("Authorization");
    if($auth == null){

        $response = Services::response();
        $response->setStatusCode(401);
        $response->setHeader("WWW-Authenticate", "Bearer Token");
        $response->setBody("{\"error\": \"unauthorized\"}");

        exit;

    }

}

If there is no authorization, I want to stop the request and return $response to client.

Right now the request is stopped, because of exit.

But as answer I get 200 OK and without body content.

How I can exit the request and set that $response to client?

ViLar
  • 1,054
  • 10
  • 18
KunLun
  • 3,109
  • 3
  • 18
  • 65
  • What do you mean by setting `$response` to client? If you want to return an HTTP 401 with the header and the body you just set you simply need to add `return $response;` instead of `exit;` – ViLar Aug 11 '20 at 14:17
  • Oh, I thought if I return something in `before`, it still execute the method from controller associated with path. But actually not. Thank you. – KunLun Aug 11 '20 at 16:31

5 Answers5

5

As mentioned in the comment, returning a Response object in the before method of a Filter prevent the execution of the controller. You don't need to use die or exit.

public function before(RequestInterface $request){

    $auth = $request->getHeader("Authorization");
    if($auth == null){

        $response = Services::response();
        $response->setStatusCode(401);
        $response->setHeader("WWW-Authenticate", "Bearer Token");
        $response->setBody("{\"error\": \"unauthorized\"}");

        return $response;

    }

}

Note that returning nothing with return; won't stop the controller from running.

ViLar
  • 1,054
  • 10
  • 18
2

use sendBody method to print content of response.

public function before(RequestInterface $request){

    $auth = $request->getHeader("Authorization");
    if($auth == null){

        $response = Services::response();
        $response->setStatusCode(401);
        $response->setHeader("WWW-Authenticate", "Bearer Token");
        $response->setBody("{\"error\": \"unauthorized\"}");
        $response->sendBody();

        exit;

    }

}
Mahdi P.
  • 167
  • 1
  • 5
0

$response is not available in before method: So I did the following in the before method to send the response and stop the execution :

      header('HTTP/1.1 401 Unauthorized', true, 401);
      die(json_encode(['error' => 'Unauthorized']));
Dhaval Chheda
  • 844
  • 1
  • 8
  • 15
  • `$response` is available through services in before method. @KunLun code is correct for this part. – ViLar Aug 12 '20 at 06:53
0

This is late but returning the response would prevent the execution of the controller.

I got a problem in the frontend from getting the error.response object of the axios response interceptor and solved it by adding the headers below.

$response = Service::response()
                   ->setContentType('application/json')
                   ->setHeader('Access-Control-Allow-Origin', 'http:://yourdomain.com');
alvinsandwich
  • 51
  • 1
  • 4
0

Today I have experienced this filtering issue myself first hand. My situation was as follows (taken from App\Config\Filters):

$globals - CSRF and Filter A

Filter A returns in the same way as @ViLar proposes.

$filters - Filter B

Filter B was a generic filter and redirects if something fails.

The problem was that in my instance, I wanted Filter B to still run but as Filter A returns a response - Codeigniter stops processing. In fact I wanted Filter B really to take precedence over Filter A. Codeigniter compiles a list of filters to apply but picks up the global first followed then by the filters array.

My solution, (and I hope this helps anyone in a similar situation) was to edit the System/Filters/Filters.php (yes that is a core system file which some may not like) and the initialize() function and move $this->processFilters($uri); above the $this->processGlobals($uri); call.

Antony
  • 3,875
  • 30
  • 32