Welcome Guest, Not a member yet? Register   Sign In
Simple authentication Library
#1

[eluser]Josh Holloway[/eluser]
I've created a simple Authentication Library (yes I know there are 100's already).

The reason for this is I like to create my own code so I know exactly what's going on and it gives me a sence of wellbeing Smile

So far I have the following:

auth.php (library):

Code:
class Auth {
    
    protected $ci;
    
    public function __construct()
    {
        $this->ci =&get;_instance();
        $this->ci->load->model('Auth_model');
        $this->ci->load->library('session');
    }
    
    public function logged_in()
    {
        //checks if the username is set in the session
        return (bool) $this->ci->session->userdata('username');
    }
    
    public function login($username, $password)
    {
        //returns TRUE/ FALSE based on what the model returns
        return $this->ci->Auth_model->login($username, $password);
    }
    
    public function logout()
    {
        //unset userdata and destroy session
        $data = array(
                    'user_id',
                    'username',
                    'group_id'
                    );
        $this->ci->session->unset_userdata($data);
        $this->ci->session->sess_destroy();
    }
    
    public function group_level()
    {
        //checks the group level the user in
        return $this->ci->Auth_model->check_group($this->ci->session->userdata('group_id'));
    }
}

auth_model.php (model):
Code:
class Auth_model extends model
{
    public function __construct()
    {
        parent::__construct();
        $this->load->library('session');
    }
    
    public function login($username, $password)
    {
        //checks if we've been fed empty string and that username exists
        if (empty($username) OR empty($password) OR ! $this->check_username($username))
        {
            return FALSE;
        }
        
        //SELECT * FROM users WHERE username = $username LIMIT 1
        $query=$this->db->where('username', $username)
            ->limit(1)
            ->get('users');
            
        //if a result is returned
        if($query->num_rows() == 1)
        {
            //get the row
            $result = $query->row();
            
            //check if password is correct
            if(md5($password) == $result->password)
            {
                //delete current session
                $this->session->sess_destroy();
                //create a new one
                $this->session->sess_create();
                
                //then set the session data with username, group ID  and user ID
                $data = array(
                    'user_id'     => $result->user_id,
                    'username'    => $result->username,
                    'group_id'    => $result->group_id
                    );
                $this->session->set_userdata($data);
                
                //sucess
                return TRUE;
                
            }
        }
        
        //password mismatch
        echo FALSE;
        
    }
    
    protected function check_username($username)
    {
        //if the username is empty return FALSE
        if(empty($username))
        {
            return FALSE;
        }
        
        //SELECT * FROM users WHERE username = $username
        $this->db->where('username', $username);
        
        //return the results
        return $this->db->get_where('users')->num_rows() > 0;
    }
    
    public function check_group($group_id)
    {
        //if the group_id is empty return FALSE
        if(empty($group_id))
        {
            return FALSE;
        }
        
        //SELECT group_id FROM groups WHERE group_id = $group_id
        $query=$this->db->select('group_id')
            ->where('group_id', $group_id)
            ->get('groups');
        
        //if a result is returned
        if($query->num_rows() == 1)
        {
            //get the row
            $result = $query->row();
            
            //return the group ID
            return $result->group_id;
        }
        
    }
}

example controller:

Code:
class Dashboard extends MX_Controller {

    function __construct()
    {
        parent::__construct();
        $this->load->model('Dashboard_model');

    }
    
    //shows the dashboard
    function index()
    {
        //if the user is logged in show the page
        if($this->auth->logged_in())
        {
            //set the required variables from the session data
            $data['current_user']    = ($this->session->userdata('username'));
            $data['group_level']    = ($this->session->userdata('group_id'));
            $data['content']        = ('dashboard');
            
            //get number of posts, categories, products and orders
            $data['count_posts']        = $this->Dashboard_model->count('posts');
            $data['count_categories']    = $this->Dashboard_model->count('categories');
            $data['count_products']        = $this->Dashboard_model->count('products');
            $data['count_orders']        = $this->Dashboard_model->count('orders');
            
            $this->load->view('admin/template', $data);
        }
        else
        {
            //if the session isn't set redirect to the site
            redirect('site');
        }
    }

I've also made it possible to restrict access to certain areas based on user level using
Code:
<?php
    if($group_level <= 2)
    {
        //some code here...
    }
?&gt;

So, what I'm asking is, what features do you feel I should add and, are there any suggestions on changes I should make to this?

I'm planning on adding a function which will setup the users DB as required for the library.

Tips/ recommendations welcome Smile
#2

[eluser]Pschilly[/eluser]
Looks good. Very clean and concise.
#3

[eluser]Josh Holloway[/eluser]
Thanks @Pschilly.

I'm looking to add remember me functionality next.

Just trying to decide the best way of doing it. I'm assuming I'll need to somehow set the sess_expiration to 0 rather than 7200 (2 hours).
#4

[eluser]mdvaldosta[/eluser]
Very nice and clean. Yeah, remember me is a pretty important one as well and I'd like to see how you do it (I haven't done that yet with any of the sites I've made in CI).
#5

[eluser]Josh Holloway[/eluser]
I've now added reset capabilities for users.

If the user clicks the link forgotten password it displays a form asking for username and email address.

The login controller has had the below added:
Code:
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function forgotten_password()
    {
        //load forgotten passowrd form
        $data['content'] = ('forgotten_password');
        
        $this->load->view('login/template', $data);    
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function reset_password()
    {
        //if the username and password supplied returns TRUE
        if($this->auth->reset_password($this->input->post('username'), $this->input->post('email_address')))
        {
            //get page showing sucessful sending of email
        }
        
        $this->forgotten_password();
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function password_form()
    {
        //if the URI given isn't found in the db returns FALSE
        if( ! $this->auth->check_url($this->uri->segment(3)))
        {
            return FALSE;
        }        
        
        //load the form to enter new password
        $data['content'] = ('password_form');
        
        $this->load->view('login/template', $data);    
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function change_password()
    {
        //if the password change returns TRUE
        if($this->auth->change_password($this->uri->segment(3), $this->input->post('password')))
        {
            //redirct to login page
            redirect('login');
        }
    }
}
/* End of file login.php */

I've added the below to my auth.php library file:
Code:
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function reset_password($username, $email_address)
    {
        //if the username and password given aren't correct return FALSE
        if( ! $result = $this->ci->Auth_model->verify_reset($username, $email_address))
        {
            return FALSE;
        }
        
        //creates a unique 1 time hash based on the time and users email address
        $time = time();
        $email = $result->email_address;
        $url = sha1($email.$time);
        
        //creates an email and sends it the email address listed in the db
        $subject = 'Subject';
        $message = site_url('login/password_form/'.$url);
        
        $this->ci->email->from('[email protected]', 'Password Reset');
        $this->ci->email->to($result->email_address);
        $this->ci->email->subject($subject);
        $this->ci->email->message($message);
        $this->ci->email->send();
        
        echo $this->ci->email->print_debugger();
        
        //if the email doesn't send
        //if( ! $this->ci->email->send())
        //{
        //    return FALSE;
        //}
        
        //if we're unable insert the URI return FALSE
        if( ! $this->ci->Auth_model->insert_url($url, $username))
        {
            return FALSE;
        }
            
        return TRUE;
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function change_password($url, $password)
    {
        //returns TRUE/ FALSE based on what the model returns
        return $this->ci->Auth_model->change_password($url, $password);
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function check_url($url)
    {
        //returns TRUE/ FALSE based on what the model returns
        return $this->ci->Auth_model->check_url($url);
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
}
/* End of file auth.php */
#6

[eluser]Josh Holloway[/eluser]
Auth_model.php file:

Code:
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function verify_reset($username, $email_address)
    {
        //if the username or email are empty return FALSE
        if(empty($username) OR empty($email_address) OR ! $this->check_username($username))
        {
            return FALSE;
        }
        
        $data = array(
            'username'        => $username,
            'email_address'    => $email_address
        );
        //SELECT * FROM users WHERE username = $username AND email_address = $email_address
        $query = $this->db->where($data)
            ->get('users');
        
        //if a result is returned
        if($query->num_rows() == 1)
        {
            //get the row
            return $result = $query->row();
        }    
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function insert_url($url, $username)
    {
        if(empty($url) && empty($username))
        {
            return FALSE;
        }
        
        //insert the url hash into the db
        $query = $this->db->where('username', $username)
            ->update('users', array('reset_url' => $url));
        
        if( ! $query)
        {
            return FALSE;
        }
        
        return TRUE;
    }                
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function check_url($url)
    {
        if(empty($url))
        {
            return FALSE;
        }
        
        //SELECT * FROM users WHERE reset_url = $url
        $query = $this->db->where('reset_url', $url)
            ->get_where('users')->num_rows() > 0;
        
        if( ! $query)
        {
            return FALSE;
        }
                    
        return TRUE;
    }
//----------------------------------------------------------------------------------------------------------------------------------------------
    public function change_password($url, $password)
    {
        if(empty($password))
        {
            return FALSE;
        }
        
        //SELECT * FROM users WHERE reset_url = $url
        $query = $this->db->where('reset_url', $url)
            ->get_where('users')->num_rows() > 0;
        
        if( ! $query)
        {
            return FALSE;
        }
        
        $blank_url ='';
        $this->db->where('reset_url', $url)
            ->update('users', array('reset_url' =>$blank_url, 'password' => md5($password)));
            
        return TRUE;
    }    
}
/* End of file auth_model.php */

The library sends the user an email containing a unique link that's stored with the user in the database.

Once the user clicks this and the password is changed the link is deleted from the db to stop the password being reset with the same URL.

Again... tips are welcome.

I'm not 100% happy with the naming conventions I've used for the functions of the password reset.

If anyone has any input for names please let me know.

- working on registration, activation and remember me functions in the near future.
#7

[eluser]-[/eluser]
hey,, hey,,,

where I can download package files above ...?

ready-made packages to codeigniter.2.0.0 +
#8

[eluser]Vheissu[/eluser]
Awesome stuff. Looks like a pretty good auth library you've written here. I'll try it out later one!
#9

[eluser]Unknown[/eluser]
This looks lightweight and simple, I will spend some time with it today. One thing I noticed that might clean up your code a little more is your login() function. Instead of getting the user then comparing the password, why not just include the password in your select statement. That way if there is a return, you know it's valid, if no return, the password was incorrect.

Currently:
Code:
$query = $this->db->where('username', $username)->limit(1)->get('users');
            
if ($query->num_rows() == 1) {
    $result = $query->row();

    if (md5($password) == $result->password) {
        // Delete current session, Create new session, Set user data
        return TRUE;
    }
    return FALSE;

Could be as simple as:
Code:
$query = $this->db->where(array('username' => $username, 'password' => $password))->limit(1)->get('users');
if ($query->num_rows() == 1) return FALSE;

// Delete current session, Create new session, Set user data
return TRUE;

Just my thoughts. Keep up the good work!
#10

[eluser]Josh Holloway[/eluser]
[quote author="ndcisiv" date="1297719375"]This looks lightweight and simple, I will spend some time with it today. One thing I noticed that might clean up your code a little more is your login() function. Instead of getting the user then comparing the password, why not just include the password in your select statement. That way if there is a return, you know it's valid, if no return, the password was incorrect.

Currently:
Code:
$query = $this->db->where('username', $username)->limit(1)->get('users');
            
if ($query->num_rows() == 1) {
    $result = $query->row();

    if (md5($password) == $result->password) {
        // Delete current session, Create new session, Set user data
        return TRUE;
    }
    return FALSE;

Could be as simple as:
Code:
$query = $this->db->where(array('username' => $username, 'password' => $password))->limit(1)->get('users');
if ($query->num_rows() == 1) return FALSE;

// Delete current session, Create new session, Set user data
return TRUE;

Just my thoughts. Keep up the good work![/quote]

Because, my good friend, in my recent codings (planned release as soon as I have time to tidy everything up) will be the ability to check the username for creating the user.

So, trying to stick to the DRY principle, I can simply check the username is available using the check username function.




Theme © iAndrew 2016 - Forum software by © MyBB