CodeIgniter Forums

Full Version: Create an authentication library on 'Build a CMS in CodeIgniter' tutsplus
You're currently viewing a stripped down version of our content. View the full version with proper formatting.

El Forum

[eluser]Lykos22[/eluser]
Hi I'd like some feedback please. I 'm quite new to CodeIgniter and I have been recently studying the tutorial Build a CMS in CodeIgniter on tutsplus and following it step-by-step. This is the part I'm most interested in:
Code:
<?php
class User_M extends MY_Model
{

protected $_table_name = 'users';
protected $_order_by = 'name';
public $rules = array(
  'email' => array(
   'field' => 'email',
   'label' => 'Email',
   'rules' => 'trim|required|valid_email|xss_clean'
  ),
  'password' => array(
   'field' => 'password',
   'label' => 'Password',
   'rules' => 'trim|required'
  )
);
public $rules_admin = array(
  'name' => array(
   'field' => 'name',
   'label' => 'Name',
   'rules' => 'trim|required|xss_clean'
  ),
  'email' => array(
   'field' => 'email',
   'label' => 'Email',
   'rules' => 'trim|required|valid_email|callback__unique_email|xss_clean'
  ),
  'password' => array(
   'field' => 'password',
   'label' => 'Password',
   'rules' => 'trim|matches[password_confirm]'
  ),
  'password_confirm' => array(
   'field' => 'password_confirm',
   'label' => 'Confirm password',
   'rules' => 'trim|matches[password]'
  ),
);

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

public function login ()
{
  $user = $this->get_by(array(
   'email' => $this->input->post('email'),
   'password' => $this->hash($this->input->post('password')),
  ), TRUE);
  
  if (count($user)) {
   // Log in user
   $data = array(
    'name' => $user->name,
    'email' => $user->email,
    'id' => $user->id,
    'loggedin' => TRUE,
   );
   $this->session->set_userdata($data);
  }
}

public function logout ()
{
  $this->session->sess_destroy();
}

public function loggedin ()
{
  return (bool) $this->session->userdata('loggedin');
}

public function get_new(){
  $user = new stdClass();
  $user->name = '';
  $user->email = '';
  $user->password = '';
  return $user;
}

public function hash ($string)
{
  return hash('sha512', $string . config_item('encryption_key'));
}
}

AND

<?php
class User extends Admin_Controller
{

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

        ...

public function login ()
{
  // Redirect a user if he's already logged in
  $dashboard = 'admin/dashboard';
  $this->user_m->loggedin() == FALSE || redirect($dashboard);
  
  // Set form
  $rules = $this->user_m->rules;
  $this->form_validation->set_rules($rules);
  
  // Process form
  if ($this->form_validation->run() == TRUE) {
   // We can login and redirect
   if ($this->user_m->login() == TRUE) {
    redirect($dashboard);
   }
   else {
    $this->session->set_flashdata('error', 'That email/password combination does not exist');
    redirect('admin/user/login', 'refresh');
   }
  }
  
  // Load view
  $this->data['subview'] = 'admin/user/login';
  $this->load->view('admin/_layout_modal', $this->data);
}

public function logout ()
{
  $this->user_m->logout();
  redirect('admin/user/login');
}

public function _unique_email ($str)
{
  // Do NOT validate if email already exists
  // UNLESS it's the email for the current user
  
  $id = $this->uri->segment(4);
  $this->db->where('email', $this->input->post('email'));
  !$id || $this->db->where('id !=', $id);
  $user = $this->user_m->get();
  
  if (count($user)) {
   $this->form_validation->set_message('_unique_email', '%s should be unique');
   return FALSE;
  }
  
  return TRUE;
}
}

What I'd like to do is to try to abstract the login, logout and all other functions that has to do with authentication from the user model and write it on a seperate simple authentication library, just for further educational knowledge, but I'm not quite sure on how I should do it, basicly how should I seperate all functions from user model and make them more generic in order to create a library. Do I have to make the table name dynamic, how to fetch user data and join them with the cms application (e.g. a message saying 'Welcome Admin'), include the session class inside my library or not and some more stuff like that.

El Forum

[eluser]JoostV[/eluser]
Create an auth library. Make sure table name and credential field names (email, password) are dynamic. You can access $this->db things by fetching the CI superobject in your library with get_instance().

Code:
protected $tablename = 'users';
protected $loginfiels = 'email';
protected $passwordfield = 'password';

public function __construct() {
    $this->ci =& get_instance();
}

Have a look at IonAuth. Great library, and certainly worth while to learn from!
Also, on a real world project you are probably better of using a well developed library like IonAuth.

El Forum

[eluser]ivantcholakov[/eluser]
See http://ellislab.com/forums/viewthread/237632/. You maybe will find something useful for your library.

I also think, that you may pick up some already developed library.

El Forum

[eluser]Lykos22[/eluser]
Sorry for the late reply and thank you both.

@JoostV: So I simply take all the 'authentication' functions of the user model and controller and the $rules and $rules_admin and put them in an other file-library (eg authentiation.php), with what you've said (dynamic db table and field names), am I right? Do I also need to include and other libraries too, like Session or Form validation, or those should be remain on my User Controller or other application controllers?

p.s. I have downloaded ion to use as a guide, but it seems too complicated.

El Forum

[eluser]Lykos22[/eluser]
I'd like some feedback about the database schema and the library. I have 2 plans on my mind and I'd like to know which one is the best to keep.

Lets say for example that I have a web shop.

1st. The library will adapt to many tables and each table will contain all data, like this:
Code:
CREATE TABLE IF NOT EXISTS `admins` (
  `admin_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `email` varchar(100) NOT NULL,
  `password` varchar(128) NOT NULL,
  `salt` varchar(128) DEFAULT NULL,
  `admin_level` tinyint(4) unsigned NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `email` varchar(100) NOT NULL,
  `password` varchar(128) NOT NULL,
  `salt` varchar(128) DEFAULT NULL,
  `first_name` varchar(50) NOT NULL,
`last_name` varchar(50) NOT NULL,
`address` varchar(50) NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

So customers/simple-users and administrators will be stored in different tables. simple-users in 'users' and administrators in 'admins'

2nd. A quite similar to Ion's database. Keep all common data ( 'username', 'email', 'password', 'salt') in a same table for both users and admins and assign additional user data, like this:
Code:
CREATE TABLE IF NOT EXISTS `users` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `email` varchar(100) NOT NULL,
  `password` varchar(128) NOT NULL,
  `salt` varchar(128) DEFAULT NULL,
  `group_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `user_groups` (
  `group_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `group` varchar(20) NOT NULL, // admin, employee, customer etc etc
  `description` varchar(100) NOT NULL,
  PRIMARY KEY (`group_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS `user_profiles` (
  `profile_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `name` varchar(100) NOT NULL,
  `address` varchar(100) NOT NULL,
  `zip` varchar(10) NOT NULL,
  `city` varchar(50) NOT NULL,
  `phone` int(10) NOT NULL,
  PRIMARY KEY (`profile_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;