4

I have Ion Auth properly installed and working on my server. I also have the default CodeIgniter 2 "news" tutorial working in the same CI installation. I'm just playing around and curious about the proper way to use the authentication system to "enclose" or protect an entire application.

For this question, let's use the "news" tutorial that comes with CI.

Inside the index() function in my news.php controller, I added conditional code to check if the user is logged in. If not, the user is just taken to the login screen.

public function index() {
    $data['news'] = $this->news_model->get_news();
    $data['title'] = 'News archive';
    if ($this->ion_auth->logged_in()) {
        $this->load->view('templates/header', $data);
        $this->load->view('news/index', $data);
        $this->load->view('templates/footer');
    } else {
        redirect('auth/login', 'refresh');
    }
}

I can see this works, but the immediate downside is that every function within the controller would also have to be modified with similar conditional logic to protect all other page views. e.g. - check for login, display page, else go to login page... over and over.

Is this the way it's supposed to be done?

What if an application is already built and working and one simply wants to protect it all? Adding conditional logic to check login status on every single page view within the controller seems unnecessarily verbose.

Can the whole application (all views) be protected in one place to minimize code modification? If so, how?

Sparky
  • 98,165
  • 25
  • 199
  • 285

3 Answers3

10

To protect an entire controller, you can put the auth check into the __construct() call as eric.itzhak mentioned.

To protect an entire application, you can extend the CI_Controller class, put the auth in the constructor of that file, and then finally extend by MY_Controller instead of CI_Controller in each of your controllers.

Code examples:

/* File: application/core/MY_Controller.php */
class MY_Controller extends CI_Controller
{
    function __construct()
    {
        parent::__construct();

        if ( ! $this->ion_auth->logged_in())
        {
            redirect('auth/login');
        }
    }
}

And then, in each controller (note MY_Controller, not CI_Controller):

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

    // rest of controller methods
}

These code examples assume you're autoloading (you might as well) the ion auth library. If not, load the library in the MY_Controller file as necessary.

There are two advantages to this method:

  1. You only have to change the CI_Controller to MY_Controller in each controller you want to protect.
  2. You don't have to protect everything which is helpful if you need to have an unprotected controller, i.e. the controller containing the auth methods (you won't be able to login if your auth controller requires you to be logged in :P -- there will be a redirect loop).
Brendan
  • 4,565
  • 1
  • 24
  • 39
  • I really like this. I wonder if there are any technical advantages besides the semantics. – Sparky Nov 30 '12 at 20:11
  • There's not really much of a difference other than (potentially) drastically reducing the amount of code you have to copy to each controller (i.e., it's DRY). I prefer this method simply because it's clean. – Brendan Dec 02 '12 at 05:24
2

Constructor is the way to go. Something else to think about -- its going to be more flexible if you call your own method instead of Ion Auth directly. typically part of the logged in process is getting unique values that are shown in the view, or an id used to keep track of the session, etc etc. Example: show the user name on the page.

So push the ion auth logged in check to a model, add a method for getting the user info or whatever you need. for each method return false if it doesn't work. and then in your constructor check if it was returned

function __construct() {
    parent::__construct();
 // load the model
 $this->load->model( 'customer_model' );

 // if logged in, return $this->customer, available to all methods in class
 if(! $this->customer = $this->customer_model->verifyLogin() ) 
 { redirect('auth/login', 'refresh'); }
 } 

 public function index()
 {
   // pass customer to data 
  $data['customer'] = $this->customer ;

 // $customer->name will now be available in view


 } 
cartalot
  • 3,147
  • 1
  • 16
  • 14
1

I think the right logic would be to check the user status inside the __construct method as it will be done each time the controller is used. it won't protect the entire ci application, just the methods in this controller, but i think this will do for your case.

Try this :

 public function __construct()
   {

        if (!$this->ion_auth->logged_in()) 
             redirect('auth/login', 'refresh');
   }
eric.itzhak
  • 15,752
  • 26
  • 89
  • 142
  • How do you mean, _"it won't protect the entire ci application"_? This would protect the entire "news" tutorial though, right? – Sparky Nov 29 '12 at 23:13
  • an application can be alot of controllers that do alot of things, this protects just the controller you are using. in this case it will make the entire news tutorial protected yes, but you should understand the concept in a few more tutorials. you should read about MVC to understand how CI works. – eric.itzhak Nov 29 '12 at 23:14
  • When answering, assume I've read all of the CI documentation, a lot of CI tutorials, and understand the MVC concept. Please don't avoid answering specific questions by referring me back to something generic. Because I seek more details at this point, and that's why I posted this question- to learn. And if your solution only protects the current model, is there any way to protect the whole application? – Sparky Nov 29 '12 at 23:30
  • Nothing that i know of, but i don't think this much work to add this to your controlers, However i think you might try creating some custom library which checks logged in on construct and autoload it. – eric.itzhak Nov 29 '12 at 23:30
  • Don't get me wrong, I really like your suggestion and it seems to work, but you're giving me the impression you don't seem entirely sure about it. – Sparky Nov 29 '12 at 23:32
  • I'm sure my code above will work in the controller, and i'm definitly not sure about the 2nd suggestion, technically it should work but i can't garantuee as i've never tried it. – eric.itzhak Nov 29 '12 at 23:34
  • on 2nd thought if you autoload your custom class then the user will never be able to login as that will be loaded in the `auth` controller as well. – eric.itzhak Nov 29 '12 at 23:40
  • Just to provide some support for @eric.itzhak here. I protect my application on a per function basis through a codeigniter helper. Yes it is more work to do this but it allows me to make any page public private or allow access to particular users at particular places. This, in my opinion, is the simplest way to protect your application while allowing access to different groups of users. For example an admin user might be the only one allowed in a function or controller that allows modifications to your users table but you wouldn't want a normal user to have access to that page. – Will Sampson Nov 30 '12 at 01:11
  • eric.itzhak is correct to say that it won't protect your entire application. You would be best to create your own MY_Controller that extends the CI_Controller. Then in the MY_Controller constructer use the above code. This will then run the code in every method of every controller that extends MY_Controller. Protecting your entire application should it expand beyond the News Controller. – Jeemusu Nov 30 '12 at 02:22