Help with beginner login questions - El Forum - 03-16-2009
[eluser]Flying Fish[/eluser]
@jedd
you mentioned sharing some of your code a couple of posts back
I think I could use the help if you don't mind of course :-)
I don't think security will be an issue, as I'm not dealing with any sensitive info
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
[quote author="Flying Fish" date="1237235544"]the logout function should destroy the whole session[/quote]
Is that a requirement? For my stuff I just test if one session variable is set or not, and looking at the code you posted earlier this library works similarly - it looks for a 'logged_in' session var - this alone determines if you're logged in or not.
Destroying the entire session is one way of removing that session variable, but it seems an extreme response.
Can you query the author of your library on the right way of using it?
Help with beginner login questions - El Forum - 03-16-2009
[eluser]Flying Fish[/eluser]
Perhaps destroying the session is a bit extreme. It was just the way the user get's logged out in the library.
I think I've got it working. Instead of loading the view I actually needed to redirect back the welcome screen
this is the logout function in the class
[code]
function logout()
{
$this->authentication->logout();
redirect('/welcome/' , 'refresh');
}
[code]
this is the logout method in the authentication library
[code]
function logout() {
$CI =& get_instance();
//Destroy session
$CI->session->sess_destroy();
}
[code]
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
To paraphrase the great man himself .. Hell is other people's code. So take this with the same caution you took the other auth library.
My model is straightforward and is (substantively) as follows. Note that this model fronts (or will front) all my authentication checks against the DB, as well as handling all member information - this means it'll watch over many tables, ultimately.
Code: <?php
/** =========================================================================
* Model - Member
*
* Interface to the people - members, auth system, groups, roles
*
* Relied upon primarily by:
* the @link People Controller
*/
class Member extends Model {
/** =========================================================================
* Attributes
**/
// Don't think we'll use any - too often we'll be talking about
// non-currently-logged-in user through this model.
/** =========================================================================
* Constructor
*/
function Member () {
parent::Model();
}
/** =========================================================================
* Authenticate by user/pass
*
* Will populate the session user data at the same time.
*
* @access public
* @param $in_user supplied by user
* @param $in_pass supplied by user (original, unencrypted)
* @return boolean
*/
function authenticate ($in_name = NULL , $in_pass = NULL) {
if ( ($in_name == NULL) OR ($in_pass == NULL) )
return FALSE;
$query = $this->db->query ('SELECT member.id, admin, password, login_name,
theme.name as theme
FROM member, theme
WHERE member.login_name="' . $in_name .'"
AND member.theme = theme.id');
if ($query->num_rows() != 1)
return FALSE;
// Okay, we've matched username, now test password
$result = $query->row_array ();
if ($result['password'] == md5($in_pass)) {
// Could do the entire array, but I prefer to track & minimise what session data is used
$this->session->set_userdata ('login_name', $result['login_name']);
$this->session->set_userdata ('admin', $result['admin']);
$this->session->set_userdata ('theme', $result['theme']);
return TRUE;
}
else
return FALSE;
} // end-method authenticate()
/** =========================================================================
* Logout
*
* Exactly what it sounds like.
* o removes session data
* o updates database with logout time
*
* Undecided whether to use this function to allow admin to log someone else out ... ?
*
* @access public
* @param $login_name supplied, but could be assumed ..?
* @return boolean
*/
function logout ($login_name = NULL) {
if ( ($login_name == NULL) )
$login_name = $this->session->userdata('login_name');
if (! $login_name)
return FALSE;
// @TODO - database updates - last login, etc.
$this->session->unset_userdata ('login_name');
$this->session->unset_userdata ('admin');
$this->session->unset_userdata ('theme');
return TRUE;
} // end-method authenticate()
Caveats for the above include: Work in progress, Theme management can be ignored, Architecture of using model as real object (replete with attributes) still being considered (see current thread elsewhere), Code snippet does is not complete (things like lookup_x, update_y, etc - not included).
Database schema FYI:
Code: CREATE TABLE member ( # the USER table, by any other name.
id SERIAL,
appellation bigint, # FK to appellation table (later)
login_name char(50) UNIQUE,
first_name char(50),
surname char(50),
password char(32), # MD5, of course
last_login datetime,
created datetime,
theme int, # FK to theme table (later)
admin BOOLEAN DEFAULT '0', # LATER - work out a better ACL / Permission system
INDEX (login_name),
PRIMARY KEY (id)
);
# Test data
INSERT INTO
member (login_name, appellation, first_name, surname, password, created, theme, admin)
VALUES (
"admin",
(SELECT id FROM appellation WHERE text="Prince Regent"),
"Administrator",
"Administrator",
MD5("secret"),
now(),
(SELECT id FROM theme WHERE name="grey"),
1
);
Caveats on schema - Work in progress, Theme table contains id/name/longname/description, Appellation contains id/text. These can be ignored, but may be of relevance if you're heading in a similar direction. Other tables are yet to be produced but obvious early candidate is some way to log activity.
Controller code to follow.
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
Controller code looks like this:
Code: <?php
/** =========================================================================
* Controller - People
*
* To view information about people.
*
* @author jedd
* @package pdb
* @version v0.9
*
*/
class People extends MY_Controller {
/// Attributes
/** =========================================================================
* Constructor
**/
function People() {
parent::MY_Controller();
/// Models
$this->load->model ('member');
/// Helpers
$this->load->helper ('url');
$this->load->helper ('html');
/// Debug profiling
// $this->output->enable_profiler(TRUE);
/// Stuff we want to do for all these methods
} // end-constructor People()
/** =========================================================================
* @TODO - an entry page for people probably makes sense.
*
* Or redirect to 'me' ?
*/
function index() {
$this->data['main_text_view'] = "You shouldn't be here";
$this->load->view ('default', $this->data);
}
/** =========================================================================
* Login
*
* Exactly what it sounds like.
*
* @access public
* @param none (other than search form results)
* @return no idea yet
*/
function login ( ) {
/// Method-specific libraries
$this->load->library('form_validation');
/// Method-specific helpers
$this->load->helper('form');
/// Rules for user and password fields
$this->form_validation->set_rules('in_login', 'User name',
'trim|required|min_length[3]|xss_clean');
$this->form_validation->set_rules('in_pass', 'Password',
'trim|required|min_length[3]|xss_clean');
/// If the user's already logged in, offer them a choice:
if ($current_login_name = $this->session->userdata('login_name')) {
// This is where we test if we're on a redirect() - so show top-bar-div username.
if ($this->session->flashdata("just_logged_in") )
$this->data['main_text_view'] = "Welcome back, <b>". $current_login_name ."</b>";
else
$this->data['main_text_view'] = "You are already logged in as <b>".
$current_login_name ."</b><br /><br />You need to ".
anchor ("people/logout", "logout") ." before logging in as someone else.<br />";
}
else {
if ($this->form_validation->run()) { // Valid form, so we try to authenticate
$in_login = $this->input->post('in_login');
$in_pass = $this->input->post('in_pass');
$valid_user_pass = $this->member->authenticate ($in_login, $in_pass);
if ($valid_user_pass) { // Hey - we're all good!
// This thing forces a refresh to ensure the top-nav-bar shows username.
$this->session->set_flashdata('just_logged_in', 'true');
redirect ("people/login");
}
else
$this->data['main_text_view'] = "Incorrect user / pass.<br>You can ".
anchor ("people/login", "try again");
}
else { // Invalid form, so we re-try the login page
$data['login_form_data'] = $this->_generate_login_form_data( );
$this->data['main_text_view']
= $this->load->view ('people/create_login_form', $data, TRUE);
}
}
/// @TODO - limit the number of retries somehow
$this->load->view ('default', $this->data);
} // end-method login()
/** =========================================================================
* Logout
*
* Exactly what it sounds like.
*
* @access public
* @param none (other than search form results)
* @return no idea yet
*/
function logout ( ) {
if ($this->session->userdata('login_name')) {
$this->member->logout('login_name');
}
// This is to force one refresh - to force top-bar to not show residual login_name
if ($this->session->flashdata('just_logged_out'))
$this->data['main_text_view'] = "You are logged out - Bye! <br /><br />Do you want to ".
anchor ("people/login", "login") . " again?";
else {
$this->session->set_flashdata('just_logged_out', 'true');
redirect ('people/logout');
}
$this->load->view ('default', $this->data);
} // end-method login()
Caveats include: Work in progress, Flashdata approach is a bit ugly and not sure on a preferred way of handling this (the redirect to a secondary method approach on valid-form seems a bit ugly too).
Again out of space, so shall push view into the next message.
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
Oh, form data is an array I generate (and I'm pretty consistent with it - makes it cleaner for me to pass data to forms), and here's the stuff from the end of the controller I posted first. You'd be just as well with this stuff done hard coded into your view I reckon.
Code: /** =========================================================================
* Create the login form data (array)
*
* An array only because the template (organism/search) was, and we might
* one day put in a 'forgot password' secondary form on this same page.
*
* @access private
* @param $posted_values (array) - value to re-insert into form (UNUSED with login)
* @return $search_form_data (array)
*/
private function _generate_login_form_data ( ) {
$form_data = array (
array (
"preamble" => "",
"target" => "people/login",
"input" => array (
"Username" => array (
"name" => "in_login",
"value" => "",
// "tabindex" => "0", // this seems to break tabbing between user/pass
),
"Password" => array (
"name" => "in_pass",
"value" => "",
// "tabindex" => "1", // this seems to break tabbing between user/pass
),
),
"hidden" => array (
"name" => "unused",
"value" => "unused",
),
"submit" => array (
"button" => "Login",
"name" => "login",
),
),
);
return $form_data;
}
And a view of my login form (snippet only as I embed view-loads back into a main view).
Code: <?php
/**
* create_login_form
*
* Generates the very basic user/pass form required to login.
*
* @param $array_of_values array with user & pass
*
*/
// Let the user know if something weird happened.
echo "<div class=\"validation_errors\">". validation_errors() . "</div>";
if (validation_errors())
echo "<hr>";
?>
<h2>
Log in to the PDB using your existing credentials
</h2>
<hr>
<?php
foreach ($login_form_data as $form) {
echo "\n". form_open ($form["target"]);
echo "\n". $form["preamble"] . " ";
foreach ($form["input"] as $input_preamble=>$input_data) {
echo "\n". $input_preamble . " : ";
echo form_input ($input_data);
echo " ";
}
echo "\n". form_hidden ($form["hidden"]["name"], $form["hidden"]["value"]);
echo "\n". form_submit($form["submit"]["name"], $form["submit"]["button"]);
echo "\n". form_close ();
echo "<hr>";
}
Caveats -- you can probably guess.
Help with beginner login questions - El Forum - 03-16-2009
[eluser]Flying Fish[/eluser]
Thanks jed,
I really appreciate you posting this
I'm going to looking it over.
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
Quote:I don't think security will be an issue, as I'm not dealing with any sensitive info
Oh, security caveats .. most importantly, research this stuff before you go live anywhere with real data.
I think that I am mostly covered by changing config.php settings, specifically sess_encrypt_cookie and the encryption_key.
Help with beginner login questions - El Forum - 03-16-2009
[eluser]jedd[/eluser]
Sorry .. one last code dump, promise.
In case it's not obvious, you would utilise all this gumpf, in your controller code, with something like:
Code: if ($this->session->userdata('login_name')
// stuff here that relies upon user being authenticated
else
// and if they're not ...
Out of curiosity I made up a helper - not sure if I'll use it - but I expect it could be handy if a) I create a range of helper functions, say with a common prefix, such that I can use this approach in other applications later, and b) it might be handy for tests that are more complex than just seeing if one bit of of userdata is in the session. Oh, and possibly © it might result in more readable code.
Here's my helper proof of concept - almost totally pointless, but you get the idea.
I think that the =& get_instance() call is inexpensive (it's just a pointer, not a copy, AFAIK).
Code: <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
*** PDB helper - lots of tiny functionettes.
**/
function is_logged_in() {
$CI =& get_instance();
return ($CI->session->userdata('login_name')) ? TRUE : FALSE ;
}
function is_admin() {
$CI =& get_instance();
return ($CI->session->userdata('admin')) ? TRUE : FALSE ;
}
/* End of file pdb_helper.php */
/* Location: ./system/application/helpers/pdb_helper.php */
Help with beginner login questions - El Forum - 04-09-2009
[eluser]M4rc0[/eluser]
Your helper above is very usefull jedd
I'm using it instead of extending the class (unnecessary, so far..)
I also hope that =& get_instance() is inexpensive
Thanks for sharing!
|