Benedict Lewis
Benedict Lewis

Reputation: 2813

Check route through Slim Middlewhere

I have a route as follows:

$app->get('/manager/:page', $authenticate($app), function ($page) use ($app, $secretshibe) {
  $app->render('manager/pages/' . $page . '.php', ['user' => $secretshibe->get_page($page, $app->view()->getData('user'))]);
});

to render users. I use $authenticate to check user login, which is as follows:

$authenticate = function ($app) use ($secretshibe) {
  return function () use ($app, $secretshibe) {
    if (!isset($_SESSION['user'])) {
      $_SESSION['urlRedirect'] = $app->request()->getPathInfo();
      $app->flash('error', 'Please login to see that page');
      $app->redirect('/login');
    }
  };
};

What I need to do, it have another logic check which checks if the user has paid. That can be obtained from $secretshibe->check_payment($username) which returns a bool, so my final function looks like this.

$authenticate = function ($app) use ($secretshibe) {
  return function () use ($app, $secretshibe) {
    if (!isset($_SESSION['user'])) {
      $_SESSION['urlRedirect'] = $app->request()->getPathInfo();
      $app->flash('error', 'Please login to see that page');
      $app->redirect('/login');
    }
    if (!$secretshibe->check_payment($_SESSION['user'])) {
      $app->flash('error', 'Your account has been marked as unpaid. Please pay to continue usage.');
      $app->redirect('/manager/payment');
    }
  };
};

The problem is that when it redirects to /manager/payment it uses the same route function, which checks authentication the same way. This results in the page getting stuck in a redirect loop. In order to stop this, I need to check if the requested route is /manager/payment before redirecting.

Because the $authenticate function is called as middleware, it is invoked before the route function, meaning that I cannot simply pass $page to it. What is the best way to prevent this redirect loop?

Upvotes: 0

Views: 1354

Answers (2)

Jeremy Kendall
Jeremy Kendall

Reputation: 2869

You want to register $authenticate as a Hook rather than as route Middleware.

$app->hook('slim.before.dispatch', $authenticate($app));

Alternately, you could use custom Middleware to register the hook. I've done that in quite a few projects. It might look something like this:

class MyMiddleware extends \Slim\Middleware
{
    public function call()
    {
        $app = $this->app;

        $authenticate = function ($app) use ($secretshibe) {
            // ... snip ...
        }

        $app->hook('slim.before.dispatch', $authenticate($app));

        $this->next->call();
    }
}

Here's a recent example of using Middleware to register a hook from one of my personal projects.

Upvotes: 2

MamaWalter
MamaWalter

Reputation: 2113

are you sure you need a closure in your middleware ? you could get app form \Slim\Slim::getInstance().

Also route middleware passed one argument, the matching route.

$authenticate = function ($route) use ($secretshibe) {
    // get the app instance
    $app = \Slim\Slim::getInstance();

    if (!isset($_SESSION['user'])) {
      $_SESSION['urlRedirect'] = $app->request()->getPathInfo();
      $app->flash('error', 'Please login to see that page');
      $app->redirect('/login');
    }

    if ($route->getName() !== '/manager/payment' && !$secretshibe->check_payment($_SESSION['user'])) {
      $app->flash('error', 'Your account has been marked as unpaid. Please pay to continue usage.');
      $app->redirect('/manager/payment');
    }
};

$app->get('/manager/:page', $authenticate, function ($page) use ($app, $secretshibe) {
  $app->render('manager/pages/' . $page . '.php', ['user' => $secretshibe->get_page($page, $app->view()->getData('user'))]);
});

Upvotes: 0

Related Questions