I’ve been all over, up n down with sessions and I simply cannot get anything working using them.
Essentially, here’s the logic I’m attempting to work out:
- Initial request - redirected to login interface
- Login interface form renders
- User submits login form
- Password is verified
- Create a session variable
- Home page interface rendered
6a) Check session variable on every interface request {or redirect to login} - Destroy session on logout
This is what the settings.php file looks like:
return [
'settings' => [
'displayErrorDetails' => true, // set to false in production
'addContentLengthHeader' => false, // allow the web server to send the content-length header
// renderer settings
'renderer' => [
'template_path' => __DIR__ . '/../public/assets/templates/default/',
],
// monolog settings
'logger' => [
'name' => 'infraweb-slim-app',
'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/infraweb.app.log',
'level' => \Monolog\Logger::DEBUG,
],
// session settings
'session' => [
// session cookie settings
'name' => 'INFRAWEB',
'cache_expire' => 60,
'cache_limiter' => '',
'gc_probability' => 1,
'gc_divisor' => 1,
'gc_maxlifetime' => 30 * 24 * 60 * 60,
'cookie_httponly' => true,
'cookie_secure' => false,
],
],
];
In the dependencies.php file:
....
// slim3-session
$container['session'] = function ($container) {
$settings = $container->get('settings');
$adapter = new PhpSessionAdapter();
$session = new Session($adapter);
$session->setOptions($settings['session']);
return $session;
};
....
The contents of middleware.php:
$app->add(
new Infraweb\Toolkit\Middleware\ValidateUI()
);
$app->add(
function ($request, $response, $next) {
$logger = $this->get('logger');
$session = $this->get('session');
$session->start();
$logger->addInfo(__METHOD__.' : slim-php session middleware started - calling next middleware');
$response = $next($request, $response);
$session->save();
$logger->addInfo(__METHOD__.' : slim-php session middleware saved - returning response');
return $response;
}
);
These are three route definitions that I’m essentially attempting to get employee login authentication working - all are class structures with method closures for the routing, with ui-named routes providing interfaces and the svc-login has logic intended to reroute requests based on authentication and the route requested:
$app->get('/login', Infraweb\LoginUI::class.':login')
->setName('ui-login');
$app->get('/', Infraweb\IndexUI::class.':home')
->setName('ui-home');
$app->post('/employees/login', Infraweb\Toolkit\Services\Authentication::class.':login')
->setName('svc-login');
The two middleware classes are being loaded up, I can move the order around by calling the $response = $next($request, $response); statement so I can visualize how that’s executing, but no matter what I’m doing I simply cannot get this session stuff worked out where it’s saving the session info - this is the LoginUI implementation:
public function __construct(ContainerInterface $container) {
// psr container, logger & session reference aggregate(s)
$this->container = $container;
$this->logger = $this->container->get('logger');
$this->session = $this->container->get('session');
$this->router = $this->container->get('router');
// local api service manager reference
$this->_service_manager = new EmployeeManager;
$this->logger->addInfo(__CLASS__ . ' : constucted and overhead initialized');
}
public function login($request, $response, $args)
{
// get status of 'active' login
$tokens = $request->getParsedBody();
$employee_manager = new EmployeeManager;
$authenticated = $employee_manager->isActiveEmployee($tokens['employee_username']);
// perform employee validation
if(!$authenticated || $authenticated['employee_number'] === 0) {
// no valid employee number returned - {inactive}
$this->session->set('eid', 0);
$this->session->set('authenticated', false);
$this->session->save();
$this->logger->addInfo(__METHOD__.' : inactive employee - redirecting to login interface');
return $response->withHeader('Location', $this->router->pathFor('ui-login'));
} else {
// valid employee number returned - {active}
$employee = $employee_manager->getEmployee($authenticated['employee_number']);
// varify the {salted} password and return
if(password_verify($tokens['employee_password'], $employee['password'])) {
// store the session employee information & complete the callback
$this->session->set('eid', (int)$employee['employee_number']);
$this->session->set('fullname', $employee['employee_firstname'].''.$employee['lastname']);
$this->session->set('authenticated', true);
$this->session->set('employee', serialize($employee));
$this->session->save();
$this->logger->addInfo(__METHOD__.' : active employee #['.$this->session->get('eid').'] - redirecting to home interface');
return $response->withHeader('Location', $this->router->pathFor('ui-home'));
} else {
// invalidate (unathenticated) employee & complete the callback
$this->session->set('eid', 0);
$this->session->set('authenticated', false);
$this->session->save();
$this->logger->addInfo(__METHOD__.' : credentials failure - redirecting to login interface');
return $response->withHeader('Location', $this->router->pathFor('ui-login'));
}
}
}
And in the authenticate ui middleware exists this logic:
public function __invoke(Request $request, Response $response, $next)
{
//echo('<pre>'.var_dump($next->getContainer()->get('router')).'<pre>'); exit();
$router = $next->getContainer()->get('router');
$session = $next->getContainer()->get('session');
$logger = $next->getContainer()->get('logger');
$logger->addInfo(__METHOD__.' : middleware ui authorization check');
// authorization check
if(!in_array($request->getUri()->getPath(), $this->unsecured)) {
if(!$session->has('authenticated')) {
$logger->addInfo(__METHOD__.' : unauthorized employee form request, redirecting to login interface');
return $response->withHeader('Location', $router->pathFor('ui-login'));
}
}
// pass on down the middleware chain
$response = $next($request, $response);
$logger->addInfo(__METHOD__.' : authorized, responding to initial request.');
// pass the response (return) back up the chain to display the requested route ui
return $response;
}
Apologies for Playing the Fool here, but it seems like I’m encountering a constant redirection to the login interface or the requests being honored (authenticated or not) depending on where the $next() method is called in the sequence. I hope I didn’t clutter this post up with code for no reason, it wasn’t the intention - just what I believe is the code that’s relevant to this enigma of sorts.
Ideas, thoughts, constructive criticisms, bitch slaps and/or shin kicks - bring em on. My slim framework education has gone awry here (grins sheepishly) and any experienced voices are welcomed to dogpile on this - I’m pretty certain at this point there’s some cement-headed logical mistake(s) I’m making…
Thanx in advance!