Using CAKE_ADMIN for multiple user types
A simple hack allowing to use the functionality of CAKE_ADMIN for more than one usertype.
Ever wanted to have pretty URLs for multiple separate types of users than just one, as core.php's CAKE_ADMIN allows? Try this little hack.
This is done by setting the CAKE_ADMIN define in /app/config/core.php with a string, such as "superuser". In that case, if a user accesses WEBROOT/superuser/book/add, BookController::superuser_add() will be called, rather than BookController::add() or maybe even SuperuserController::book('add') which is, of course, not what we intend to happen. This mechanism allows for prettier and more sensible URLs for these admin users.
But, Cake only supports one such admin view - if there are more types of administrators or access levels, each with their totally disjunct pages and functionality, how do we go about that? This little snippet will, albeit in a slightly ugly way, do the trick.
In the above example, calling (for instance) /member/banana/peel/3 would cause BananaController::member_peel(3) to be invoked.
The situation
By default, Cake supports a way of making specific controller actions and views for a special class of users - generally intended for administrator views.This is done by setting the CAKE_ADMIN define in /app/config/core.php with a string, such as "superuser". In that case, if a user accesses WEBROOT/superuser/book/add, BookController::superuser_add() will be called, rather than BookController::add() or maybe even SuperuserController::book('add') which is, of course, not what we intend to happen. This mechanism allows for prettier and more sensible URLs for these admin users.
But, Cake only supports one such admin view - if there are more types of administrators or access levels, each with their totally disjunct pages and functionality, how do we go about that? This little snippet will, albeit in a slightly ugly way, do the trick.
The solution
Put the following code in your /app/config/bootstrap.php:
<?php
/**
* We define CAKE_ADMIN differently for the different usertypes we
* want to support, acting on the currently called URL to decide
* which we tell Cake about.
*/
function adminHack($subdirs)
{
$firstSlash = strpos($_GET['url'],'/');
$firstSubdir = substr($_GET['url'], 0, $firstSlash);
if(in_array($firstSubdir, $subdirs))
{
define('CAKE_ADMIN', $firstSubdir);
}
}
//example usage:
adminHack(array('member', 'expert', 'superuser'));
?>
In the above example, calling (for instance) /member/banana/peel/3 would cause BananaController::member_peel(3) to be invoked.








Router::connect('/members/:controller/:action/*', array('prefix' => 'members'));
and this in the isAuthorized function of my app_controller.php
if(strpos($this->action, 'members') !== false) {
if ($this->Auth->user('role_id') == '2') {
return true;
} else {
return false;
}
}
Is this foolproof? Also is this the best way to do it in 1.2?
$url = explode('.',$_SERVER['HTTP_HOST']);
switch ($url[0]) {
case "admin":
Configure::write('Routing.admin', 'admin');
$_GET["url"] = "admin/" . str_replace('admin/','',$_GET['url']);
break;
case "support":
Configure::write('Routing.admin', 'support');
$_GET["url"] = "support/" . str_replace('support/','',$_GET['url']);
break;
default:
}
If anybody tries this and it doesn't work - remember that you need to comment out the
define('CAKE_ADMIN', 'admin');line in app/config/core.phpAre multiple admin routes a feature in 1.2?
Regarding the security issue mentioned above, try replacing the adminHack() function with something like the following code:
(It's not tested - just an idea.)
<?php
function adminHack($adminTypes) {
$bits = explode('/', $_GET['url'], 3);
if (in_array($bits[0], $adminTypes) {
// This admin route is being requested (officially)
define('CAKE_ADMIN', $bits[0]);
{
else {
$matches = array();
// Check if someone's trying to be naughty
if (preg_match('/^(' . implode('|', $adminTypes) . ')\_/', $bits[1], $matches)) {
define('CAKE_ADMIN', $matches[1]);
}
}
}
?>
This should stop URLs of the type example.com/banana/admin_peel/21.
It does this by detecting the /admin_ part of th URL and declaring that as the CAKE_ADMIN, which will convince CakePHP's default security bouncer to kick the user out - or whatever it usually does.
(Nice banana example btw - although according to the CakePHP bible the controller should be called 'BananasController').
<?php
function adminHack($adminTypes) {
$bits = explode('/', $_GET['url'], 3);
if (in_array($bits[0], $adminTypes)) {
//This admin route is being requested (officially)
Configure::write('Routing.admin', $bits[0]);
} else {
$matches = array();
// Check if someone's trying to be naughty
if (preg_match('/^(' . implode('|', $adminTypes) . ')\_/', $bits[1], $matches)) {
Configure::write('Routing.admin', $matches[1]);
}
}
}
?>
Rember to have Config:write('Routing.admin', '???'); commented in your core.php
happy hacking
<?php
function adminHack($adminTypes) {
$bits = explode('/', $_GET['url'], 3);
if (in_array($bits[0], $adminTypes) {
// This admin route is being requested (officially)
define('CAKE_ADMIN', $bits[0]);
{
else {
$matches = array();
// Check if someone's trying to be naughty
if (preg_match('/^(' . implode('|', array_map('preg_quote', $adminTypes)) . ')\_/', $bits[1], $matches)) {
define('CAKE_ADMIN', $matches[1]);
}
}
}
?>
So if someone with Your 'hack' in bootstrap will not test $this->action in access control system, or if it is depending on $this->params[CAKE_ADMIN] somehow, then he is in a big trouble.
Small typo:
adminHack_hack(array('member', 'expert', 'superuser'));
should be:
adminHack(array('member', 'expert', 'superuser'));
Comments are closed for articles over a year old