Access to my application (in order)
- Whitelist ip address
- redirect to 404 on invalid ip
- Check if last activity was > 2 hours ago
- redirect to login page and expire session
- Check if user is logged in, by looking at user data in $_SESSION
- redirect to login page if not valid
Index.php
(notice it is very similar to this question):
/**
* Set Timezone
*/
date_default_timezone_set('Zulu');
/**
* Include globals and config files
*/
require_once('env.php');
/*
* Closure for providing lazy initialization of DB connection
*/
$db = new Database();
/*
* Creates basic structures, which will be
* used for interaction with model layer.
*/
$serviceFactory = new ServiceFactory(new RepositoryFactory($db), new EntityFactory);
$serviceFactory->setDefaultNamespace('\\MyApp\\Service');
$request = new Request();
$session = new Session();
$session->start();
$router = new Router($request, $session);
/*
* Whitelist IP addresses
*/
if (!$session->isValidIp()) {
$router->import($whitelist_config);
/*
* Check if Session is expired or invalid
*/
} elseif (!$session->isValid()) {
$router->import($session_config);
/*
* Check if user is logged in
*/
} elseif (!$session->loggedIn()) {
$router->import($login_config);
} else {
$router->import($routes_config);
}
/*
* Find matched route, or throw 400 header.
*
* If matched route, add resource name
* and action to the request object.
*/
$router->route();
/*
* Initialization of View
*/
$class = '\\MyApp\\View\\' . $request->getResourceName();
$view = new $class($serviceFactory);
/*
* Initialization of Controller
*/
$class = '\\MyApp\\Controller\\' . $request->getResourceName();
$controller = new $class($serviceFactory, $view);
/*
* Execute the necessary command on the controller
*/
$command = $request->getCommand();
$controller->{$command}($request);
/*
* Produces the response
*/
echo $view->render();
The $router->import()
function takes a json file with the route configuration and creates the routes (Haven't decided if I'm going to keep that). My router is a modified version of Klein.
My Question
Is this a proper implementation of how to check the session data?
I would prefer to check that the user data in the session can be found in the database, but I would need to use a Service for that, and Services should only be accessed by the controller(?). I wouldn't know which controller to send the user to since the route configuration would change if the user was logged in.
For example, if someone was trying to go to www.myapp.com/orders/123, I would send them to the Orders controller if they were logged in, or the Session controller (to render the login page) if they weren't.
I have read the ACL Implementation from this question. But, unless I'm mistaken, that is for controlling access for users who are already logged in, not for users who aren't logged in. If this is not the case, could someone please explain how I would implement my ACL to check this?
I greatly appreciate any help since the search for this answer has given me really mixed solutions, and most of them I don't like or don't seem like clean solutions. Like a Session Manager, which is basically what I'm doing, but pretending not to. =/
UPDATED index.php (my solution)
/**
* Set Timezone
*/
date_default_timezone_set('Zulu');
/**
* Include globals and config files
*/
require_once('env.php');
/*
* Closure for providing lazy initialization of DB connection
*/
$db = new Database();
/*
* Creates basic structures, which will be
* used for interaction with model layer.
*/
$serviceFactory = new ServiceFactory(new MapperFactory($db), new DomainFactory);
$serviceFactory->setDefaultNamespace('\\MyApp\\Service');
include CONFIG_PATH.'routes.php';
$request = new Request();
$router = new Router($routes,$request);
/*
* Find matched route.
*
* If matched route, add resource name
* and command to the request object.
*/
$router->route();
$session = $serviceFactory->create('Session');
/*
* Whitelist Ip address, check if user is
* logged in and session hasn't expired.
*/
$session->authenticate();
/*
* Access Control List
*/
include CONFIG_PATH.'acl_settings.php';
$aclFactory = new AclFactory($roles,$resources,$rules);
$acl = $aclFactory->build();
$user = $session->currentUser();
$role = $user->role();
$resource = $request->getResourceName();
$command = $request->getCommand();
// User trying to access unauthorized page
if (!$acl->isAllowed($role, $resource, $command) {
$request->setResourceName('Session');
$request->setCommand('index');
if ($role === 'blocked') {
$request->setResourceName('Error');
}
}
/*
* Initialization of View
*/
$class = '\\MyApp\\View\\' . $request->getResourceName();
$view = new $class($serviceFactory, $acl);
/*
* Initialization of Controller
*/
$class = '\\MyApp\\Controller\\' . $request->getResourceName();
$controller = new $class($serviceFactory, $view, $acl);
/*
* Execute the necessary command on the controller
*/
$command = $request->getCommand();
$controller->{$command}($request);
/*
* Produces the response
*/
$view->{$command}
$view->render();
I start the session and authorize the user in the Session model. The session's currentUser will have a role of 'guest' if not logged in, or 'blocked' if it's IP address is not in the whitelist. I wanted to implement the Controller wrapper as suggested teresko's previous ACL post, but I needed something that would redirect the user's instead. I send them to their homepage (Session#index) if they try to access a page they aren't allowed to, or to Error#index if they are blocked. Session#index will let the View decide whether or not to display the homepage for a logged in user, or the login page if they aren't logged in (by checking the user's role). Maybe not the best solution, but doesn't seem too terrible.