DataMapper ORM


Handling Logins

The example application includes a fairly simple login manager. It doesn't handle anything fancy, such as registering users, emailing passwords, or allowing users to reset their password. But it does provide a foundation to see how to create users, securely encrypt their passwords, and validate logins.

Application / Models / User.php

The model handles the heavy work of hashing the password, as well as validating the login.

Some sections of the file have been trimmed for brevity, and replaced with ellipsis.

43 • 56 57 58 59 60 61 62 63 64 65 • 70 • • • 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
var $validation = array( [...] 'password' => array( 'label' => 'Password', 'rules' => array('required', 'trim', 'min_length' => 3, 'max_length' => 40, 'encrypt'), 'type' => 'password' ), 'confirm_password' => array( 'label' => 'Confirm Password', 'rules' => array('required', 'encrypt', 'matches' => 'password', 'min_length' => 3, 'max_length' => 40), 'type' => 'password' ), [...] ); [...] /** * Login * * Authenticates a user for logging in. * * @access public * @return bool */ function login() { // backup username for invalid logins $uname = $this->username; // Create a temporary user object $u = new User(); // Get this users stored record via their username $u->where('username', $uname)->get(); // Give this user their stored salt $this->salt = $u->salt; // Validate and get this user by their property values, // this will see the 'encrypt' validation run, encrypting the password with the salt $this->validate()->get(); // If the username and encrypted password matched a record in the database, // this user object would be fully populated, complete with their ID. // If there was no matching record, this user would be completely cleared so their id would be empty. if ($this->exists()) { // Login succeeded return TRUE; } else { // Login failed, so set a custom error message $this->error_message('login', 'Username or password invalid'); // restore username for login field $this->username = $uname; return FALSE; } } // -------------------------------------------------------------------- /** * Encrypt (prep) * * Encrypts this objects password with a random salt. * * @access private * @param string * @return void */ function _encrypt($field) { if (!empty($this->{$field})) { if (empty($this->salt)) { $this->salt = md5(uniqid(rand(), true)); } $this->{$field} = sha1($this->salt . $this->{$field}); } }

Application / Controllers / Login.php

The login controller simply renders out the login form (below). If the form was submitted, it attempts to process the login.

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
function index() { $user = $this->login_manager->get_user(); if($user !== FALSE) { // already logged in, redirect to welcome page redirect('welcome'); } // Create a user to store the login validation $user = new User(); if($this->input->post('username') !== FALSE) { // A login was attempted, load the user data $user->from_array($_POST, array('username', 'password')); // get the result of the login request $login_redirect = $this->login_manager->process_login($user); if($login_redirect) { if($login_redirect === TRUE) { // if the result was simply TRUE, redirect to the welcome page. redirect('welcome'); } else { // otherwise, redirect to the stored page that was last accessed. redirect($login_redirect); } } } $user->load_extension('htmlform'); $this->output->enable_profiler(TRUE); $this->load->view('template_header', array('title' => 'Login', 'hide_nav' => TRUE)); $this->load->view('login', array('user' => $user)); $this->load->view('template_footer'); }

Application / Libraries / Login_Manager.php

The login_manager library was created to make it easier to prevent unchecked access to the website. By default, when it is loaded, it will redirect to the login page if there is no login. It also contains options to restrict the access based on the user's assigned group.

This snippet below shows the method used to validate the login. The session variable login_redirect was stored at an earlier time, if the user attempted to visit a page without being logged in (or, if the session had timed out).

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
/** * process_login * Validates that a username and password are correct. * * @param object $user The user containing the login information. * @return FALSE if invalid, TRUE or a redirect string if valid. */ function process_login($user) { // attempt the login $success = $user->login(); if($success) { // store the userid if the login was successful $this->session->set_userdata('logged_in_id', $user->id); // store the user for this request $this->logged_in_user = $user; // if a redirect is necessary, return it. $redirect = $this->session->userdata('login_redirect'); if($redirect !== FALSE) { $success = $redirect; } } return $success; }

Application / Controllers / Bugs.php

Finally, to show how login_manager is used to prevent access for non-logged-in users, this is from the top of a controller.

3 4 5 6 7 8 9 10 • •
class Bugs extends Controller { function __construct() { parent::__construct(); // prevent non-logged-in access $this->load->library('login_manager'); } [...]