Blog Archive

Wednesday 19 February 2014

Creating an authentication system for Fuel CMS using the Ion Auth library and Codeigniter hooks

Fuel CMS has an excellent system for publishing pages to a website. But what if you wanted some of those pages to be "members only", protected on the front end by an authentication layer? There is no in-built method to do this, but there are plenty of ways in the underlying Codeigniter framework to enable it.

In this tutorial we will install and use the excellent Ion Auth library written for Codeigniter by Ben Edmunds to create just such an authentication layer for Fuel CMS pages.

The Ion Auth library is available as a zip from GitHub, and is already packaged in the Codeigniter directory hierarchy, so just unpack it into your Fuel CMS directory, in the /application/ folder, and run the SQL provided. We will be making use of it just as if it were running in a plain vanilla CI site.

Preparing Fuel CMS for front end authentication

From Fuel’s CMS perspective, we are going to alter the default layout (“main”) for “pages”, but we want to set Fuel’s page mode to “auto” for our purposes, so change $config['fuel_mode'] (in /application/config/MY_fuel.php) if it is set to anything else.

A bit of background on the way Fuel CMS stores "pages" might be useful to understand the concept of "layouts".

"Pages" are stored in 2 database tables in Fuel:
  1. Fuel_pages is a relatively small table which stores the id, location (uri), published status, cache mode and related author and timestamp data. This is the “parent” table.
  2. Fuel_page_variables (the “child” table) stores the actual content of the page, related by a foreign key to Fuel_pages. What makes the Pages module in Fuel so flexible is that the "layout" fields are stored as name and value pairs, which means they are easily extendable. More fields = more rows in this table.
So the HTML input fields that are evident in the Pages module of the Fuel admin system are actually configured by "layouts", which are really just PHP arrays. These array templates are then stored, in name value pairs in the Fuel _pages_variables table. Importantly, each pair is also classified by a "type", so an input field might be text, multi, date, file and so on (more info here). This means if you want to add to the fields/inputs for a page layout, you don't need to alter the SQL structure of the storage table, you just add to the PHP arrays! This is a HUGE timesaver!

If you need to have different content layouts in your site (eg your "Home" page has need of video urls, or your"About" page differs from other pages as it has formatted staff biographies) then one way to tackle these content differences is by making use of one or more layouts. The choice of layout is actually there in the page (Fuel_pages) definition. Try swapping between "main" and "alias" layouts in the pages module and see how the field layout alters completely!

To change or create new layouts, we need to edit MY_fuel_layouts.php (found in the /application/config folder). Note that if you add another layout to the MY_fuel_layouts file, then you should also provide a new layout view file in /application/views/_layouts of the same name as the config index..

However, we are going to keep things relatively simple here and just alter the "main" layout. We want simple “boolean” authentication across all the pages we create, and for the sake of this tutorial we will stick with one layout that incorporates this. So find the array definition $config['layouts']['main'] and add to the end of the "fields" sub-array this:

'auth' => array(
'type' => 'enum',
'options' => array('0' => 'No', '1' => 'Yes'))


Here we are adding a field called "auth" to the main layout. It's an enum type, so Fuel's Form Builder Class will render a radio button array (as there are only 2 values) and the values will be 0 and 1, with labels "No" and "Yes" respectively.
admin_auth_field

Save MY_fuel_layouts.php and call up the pages module in the Fuel admin to see the result. Note that because we added the value  after the Body fieldset definition, the new field "auth" will appear last under the "Body" tab in the "Layout Variables" section of the page. Select “Yes” for the new field. Now when you save the page, the selected value (1) will be stored in the Fuel_page_variables table. Try running the following SQL in your database client to verify the saved value (your page_id value may differ):

select * from fuel_page_variables where page_id = 2 and name = 'auth';

The result may look something like:

page_variable_auth_sql


Note that if you re-save that page, but with “No” selected, you will observe from running the SQL query again that the “No” value (0) is actually saved as an empty value.

Ok, so we can now flag which pages are to be protected. But how to actually check the value in the page against Ion Auth?

Using Codeigniter’s hooks

There are a few ways to implement Ion Auth in Codeigniter – we could use the controller system to create an authentication controller, and extend from that when we need to employ login credential checks. But for this tutorial we will use Codeigniter’s Hooks.

As the name implies, Hooks are means of intercepting processes in Codeigniter at crucial points. With our authentication system, we want to check at the Controller level, or very near it. One hook “post_controller_constructor” suits our requirements. It will be almost as good as writing the Ion Auth authentication into each and every controller’s constructor method. Note that doing this may introduce performance penalties as it will be run on every controller call in the application, so it is important to tread lightly using this technique!

To create a Hook, we need to add an entry to /application/config/hooks.php:

include(FUEL_PATH . 'config/fuel_hooks.php');
 
/* Our hook code for Ion Auth */
$hook['post_controller_constructor'][] = array(
    'class' => 'Auth_hooks',
    'function' => 'cms_auth',
    'filename' => 'Auth_hooks.php',
    'filepath' => 'hooks',
    'params' => array(),
    'module' => 'app',
);

Note that we add this hook definition after the include for Fuel’s own hooks, and that we employ the “multiple calls to the same hook” extra array index (this is because Fuel is already using this Hook point, so we are adding to it with the extra array dimension).

So we need to have a class called Auth_hooks.php in /application/hooks, with a method “cms_auth()”. We don’t have to use a class, but we will!

class Auth_hooks {

    function cms_auth() {
        $CI = &get_instance();
        $redirect_to = 'auth/login';
        $pagevars = $CI->fuel->pagevars->retrieve(uri_path());
        if(isset($pagevars)) {
            if(isset($pagevars['auth'])) {
                $CI->load->library('ion_auth');
                if(!$CI->ion_auth->logged_in() && $pagevars['auth'] == 1) {
                        redirect($redirect_to);
                }
            }
        }
    }
}


This is a very simple means of protecting CMS content using hooks. If the page is set to require authentication ($pagevars['auth'] == 1) and Ion_Auth detects no login credentials, then we redirect the user to the auth/login controller (which should have been added when the Ion Auth zip was unpacked). Note that we use the Pagevars class to find any variables for the given url. One other important note: turn off caching for authenticated pages - otherwise you may inadvertently store login information.

There are a number of improvements we could make to this basic authentication handling. For example, we could make it more fine grained and authenticate against Ion Auth’s groups (ie a user must be logged in and a member of group or groups x,y,z…). We could make the redirect a bit more helpful, such that after logging in the user is redirected to the original page he or she was rejected from.

All of this is possible and may be the subject of a further post!

No comments:

Post a Comment

My top artists