2

I'm currently working on CI for my website, and i'm having some trouble about extending Controller_CI. I have one controller that deals with login/signin actions, which doesn't need authentication, and others controllers that check if a user session exists before loading content.

For that purpose, I created MY_Controller class and add authentication code in the constructor. Then I made all my controller extend MY_Controller, except the first one that still extends Controller_CI

My question is : Is it the right way to deals with authentication ? Is it still possible to use Controller_CI even if it's extended ?

I found another pattern :

http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-Base-Classes-Keeping-it-DRY

I guess it's better, but still, I don't understand why not using the first solution.

Thanks

Bach
  • 45
  • 8
  • What if, even within a same class, there are methods which are needed to be authenticated and don't needed to be authenticated ? – Ijas Ameenudeen Mar 02 '14 at 08:45

4 Answers4

0

Extending controller class for that purpose will work, but this solution is not much flexible. I would rather create a library that handles authentication, and run it from a controller when it is desired. Please read http://ellislab.com/codeigniter/user-guide/general/creating_libraries.html for details about creating custom libraries in CI.

Robert Trzebiński
  • 1,327
  • 8
  • 16
0

Please remember you can only extend the CI_Controller with MY_Controller only once. In that aspects it's not a good idea. Suppose you want to implement another feature (e.g. a piece of code that makes a specific entry in the log) for some controllers, but not necessarily the controllers that need authentication you cannot make another MY_Controller.

Using a library is a better thing.

I'm using the flexi auth library on a big CI site. On every controller that requires authentication I just add the following:

public function __construct() {
    parent::__construct();

    $this->load->library('flexi_auth');

    if (!$this->flexi_auth->is_logged_in())
       redirect('auth/login');
}
Chris Aelbrecht
  • 2,051
  • 21
  • 25
  • That's exactly what i'm doing. I have a lightweight library that deals with authentication. Only difference is that the "if(logged) {do stuff} else {redirect to login} is in my MY_Controller constructor instead of being in all controllers that require authentication. – Bach Feb 21 '14 at 13:27
  • So you can either: 1. Move 'if(logged) {do stuff} else {redirect to login}' to another function in MY_Controller i.e. named auth(). 2. Run $this->auth() in your contoller every time you need to check if user is authorized. or: run 'if(logged) {do stuff} else {redirect to login}' only if some cutom parameter is passed to construct, it can be false by default, so you will run parent::__construct(true) only if auth is needed, and parent::__construct() if not – Robert Trzebiński Feb 21 '14 at 16:12
  • @Bach, since authentication is not required in all your controllers I would keep it out of the constructure of MY_Controller, but that's just my personal opinion. Technically there is nothing wrong with what you do. – Chris Aelbrecht Feb 23 '14 at 20:38
0

I think a combination of what Phil Sturgeon suggests in that blog post and using a library would be best. So I would create a core controller (by that I mean a controller you place into application/core that extends CI_Controller) called MY_Controller which will look something like this

class MY_Controller extends CI_Controller
{
    function __construct()
    {
        parent::__construct();
    }

    //Any other functions you want
}

Then judging by your question you currently have controllers that fit into two categories

  • Controllers that do require a logged in user before they do anything
  • Controllers that don't require a logged in user before they do anything

So I would then create another controller in the /application/core directory that extends MY_Controller but in its constructor it checks to see if the user is logged in

class Auth_Controller extends My_Controller
{
    function __construct()
    {
        parent::__construct();

        //Check to see if the user is logged in
        $this->load->library('authentication');

        if(!$this->authentication->user_logged_in())
        {
            redirect('/login');
        }
    }

    //Any other functions you want
}

Now when you create you controller you can choose which one of the core controllers you want to extend. If its a controller than doesn't require a logged in user you can extend MY_Controller but if it does required a logged in user you can extend Auth_Controller. That way it means you only need to do the user login check once in your code.

Like others have said if may be a good idea to place any authentication code into a library as that's a better place to put it than in a controller.

Summary

So to summarise by having all of your controllers extend core controllers rather than CI_Controller it should cut down on code repetition.

Pattle
  • 5,983
  • 8
  • 33
  • 56
0

I also currently working on a CI project and had the same issue. I have came up with a different solution to deal with the authentication.

I extended the core controller as bellow,

class MY_Controller extends CI_Controller { public $data = array(); public $calledClass ; public $calledMethod ;

public function __construct()
{
    parent::__construct();

    $authException['authentication']['login'] = true;
    $authException['authentication']['logout'] = true;
    $authException['welcome']['index'] = true;

    $this->load->library("router");

    $this->calledClass = $this->router->fetch_class();
    $this->calledMethod = $this->router->fetch_method();

    if(!@$authentication[$this->calledClass][$authentication->calledMethod] && !Auth::isUserLoggedIn())
    {
        # IS_AJAX is a contant defined in the contants.php
        # define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
        if(IS_AJAX)
        {
            # if this is an AJAX call, it sets a value in the header ,
            # which can be captured in the AJAX response
            # to redirect the user to the login page.
            $this->output->set_header("auth-him:1");
            exit;
        }
        else
        {
            redirect("authentication/login");
        }
    }
}

}

Hope the code above is clear and this helps.

To extend core controller more than one time, If you still need to use 2 controllers to handle authentication, I have followed this method

https://stackoverflow.com/a/22125436/567854

Hope this also helps :)

Community
  • 1
  • 1
Ijas Ameenudeen
  • 9,069
  • 3
  • 41
  • 54