How would you guys implement admins and mods into your app?

Hi!

I´m working on a very small project. It has two purposes. Number one: learn PHP. Number two, learn a framework. Currently it contains of a login and simple CRUD were users can create notes.

But anyway.

I have an auth middleware

        if (!$this->container->auth->check()) {
            $this->container->flash->addMessage('error', 'Please sign in before doing that.');
            return $response->withRedirect($this->container->router->pathFor('auth.signin'));
        }

This auth middleware is attached as a group in the route file

For example:

$app->group('', function () {
    $this->get('/dashboard', 'AuthController:dashboard')->setName('dashboard');

    $this->get('/notes', 'NoteController:index')->setName('notes');
    $this->post('/notes', 'NoteController:newNote')->setName('new.note');
    
    $this->get('/notes/{note_id:[0-9]+}', 'NoteController:getEditNote');
    $this->post('/notes/{note_id:[0-9]+}', 'NoteController:postEditNote')->setName('edit.note');
    $this->get('/notes/deleteNote/{note_id:[0-9]+}', 'NoteController:deleteNote')->setName('delete.note');
})->add(new AuthMiddleware($container));

But now I’m looking into the option to add Admins and mods, as a user_type. So i added user_account_typetinyint(1) NOT NULL DEFAULT '1'. And made a middleware, AdminMiddleware

    {
    	/** Check if user is admin, if not. Return 404 */
        if (!$this->container->auth->checkIsAdmin()) {
            return $response->withStatus(404)->withHeader('Content-Type', 'text/html')->write('Page not found');
        }

And somewhere here my questions popping up. I have for some testing just added this route

$app->get('/admin', function ($request,  $response, $args) {
    return 'You are signed in as admin';
})->add(new AdminMiddleware($container));

And as you can se, this Middleware dosen check if your are authenticated, but you have to be for the Model to fetch that row:

    public function checkIsAdmin()
    {
        if(User::where('user_id', $_SESSION['user_id'])->first()->user_account_type == '1'){
           return true;
       }else{
        return false;
       }
    }

So what would the best practice be to check if someone is Admin/mod etc?

A route to /admin would be pretty straight forward with a middleware, but for small things in every view, like edit, delete, ban etc

What is the best way to go/best practices of implementing admin and mods through the app?

Hi, @johan .

I’m developing a small project in my organization and I’m “solving” (it is not done, yet) this way:

  • Authentication through LDAP (Active Directory, to be honest)
  • Authorization through RDBMS (so I must maintain my own table with users and roles, if he/she is valid in LDAP Domain, and need more permissions than the “guest” role, I shall have his/her username in my own table and add roles)

I am using https://github.com/jeremykendall/slim-auth . This component is not well documented, It says 90% documented, but I think the developer means “90% for the old release” ! A mess. But works fine.

I would show you my repo template , but it is a mess too . So, basically do this (think this should be the actual doc for the component, IMHO):

  • install jeremykendall/slim-auth (using composer)

index.php :


//if you need a simpler approach, like Authenticate through RDBMS, use the Pdo Adapter provided by the package:

/*
 * RDBMS Adapter
 */
$validator = new PasswordValidator();
$adapter = new PdoAdapter( (new \PDO("mysql:host=localhost;port=3306;dbname=slim_allinone_orm", "mysqlusername", "" ))
 		, 'users', 'username', 'password', $validator); //PdoAdapter class needs params for DB connection and params like which table and columns to query


//or If you need LDAP:

/*
 * LDAP Adapter
 */
$configReader = new \Zend\Config\Reader\Ini();
$configData = $configReader->fromFile(Config::CONFIG_FILE);
$config = new \Zend\Config\Config($configData, false);
$options = $config->ldapauth->ldap->toArray();
$adapter = new Zend\Authentication\Adapter\Ldap($options);
$container["authAdapter"] = $adapter;
$slimAuthProvider = new SlimAuthProvider();
$slimAuthProvider->register($container);
/*
add middleware:
the $container["auth"] is injected into Pimple Container by the SlimAuthProvider above
*/
$app->add(new Authorization( $container["auth"], $acl, new RedirectHandler("auth/notAuthenticated", "auth/notAuthorized") ));

Now, the ACL design (Acl.php):

use Zend\Permissions\Acl\Acl as ZendAcl;
use Zend\Permissions\Acl\Resource\GenericResource;

/**
 * ACL for Slim Auth Implementation Example.
 */
class Acl extends ZendAcl
{
	protected $defaultPrivilege = array('GET');
	
	public function __construct()
	{
		// APPLICATION ROLES
		$this->addRole('guest');
		// member role "extends" guest, meaning the member role will get all of
		// the guest role permissions by default
		$this->addRole('member', 'guest');
		$this->addRole('admin');
		// APPLICATION RESOURCES
		// Application resources == Slim route patterns
		$this->addResource('/');
		$this->addResource('/login');
		$this->addResource('/logout');
		$this->addResource('/member');
		$this->addResource('/admin');
		
		$this->addResource('/home');
		$this->addResource('/hello[/{name}]');
		
		$this->addResource('/protected');
		$this->addResource('/auth/notAuthenticated');
		$this->addResource('/auth/notAuthorized');
		// APPLICATION PERMISSIONS
		// Now we allow or deny a role's access to resources.
		// The third argument is 'privilege'. In Slim Auth privilege == HTTP method
		$this->allow('guest', '/', $this->defaultPrivilege);
		$this->allow('guest', '/login', array('GET', 'POST'));
		$this->allow('guest', '/logout', $this->defaultPrivilege);
		$this->allow('member', '/member', $this->defaultPrivilege);
		
		$this->allow('guest', '/home' , $this->defaultPrivilege);
		$this->allow('guest', '/hello[/{name}]' , $this->defaultPrivilege);
		$this->allow('guest', '/auth/notAuthenticated' , $this->defaultPrivilege);
		$this->allow('guest', '/auth/notAuthorized' , $this->defaultPrivilege);
		$this->allow('admin', '/protected' , $this->defaultPrivilege);
		
		// This allows admin access to everything
		$this->allow('admin');
	}
	
}
  • read this[1] if you too need to assign more than one role to the same user (I tested, it looks nice, but the object $roleOrUser depends on the authentication. I use LDAP, so the model is different)

[1] http://stackoverflow.com/questions/14540445/zend-acl-how-to-check-a-user-with-multiple-roles-for-resource-access