Welcome Guest, Not a member yet? Register   Sign In
Login (Checking exists (Using callback) and then checking against the DB
#1

[eluser]JamieBarton[/eluser]
Hi there,

I'm in the middle of creating a login system. I have created the necessary parts to check against the DB for the user, this is inside a call back named 'callback_check_exists'.

What I would like to do is check that the account is activated, in the DB i have a column for user_activated (with a default of 0) (1 meaning activated). But I would like to when the form is submitted check the user exists (the callback_ validation) and if so, then check if the user is activated, if so, continue and allow me to store the session data. How can I take the data that is returned in the callback (it selects all from the db, and returns it as $query. I obviously need the ID to make a new model function to check if that ID is activated..

Here is my controller:
Code:
function login()
    {
        if (!$this->auth->logged_in()) {
            
            $this->form_validation->set_rules('username', 'Username', 'trim|required|callback_check_exists');
            $this->form_validation->set_rules('password', 'Password', 'trim|required');
            
            if ($this->form_validation->run() == FALSE) {
                $this->layout->view('session/login');
            } else {
                $this->output->redirect(self::SUCCESS_PAGE);
            }
        } else {
            $this->output->redirect(self::SUCCESS_PAGE);
        }
    }
    
    function check_exists()
    {
        $this->load->model('usersmodel', 'users');
        
        $username    = $this->input->post('username');
        $password    = md5($this->input->post('password'));
        
        if ($this->users->find_user_by_login($username, $password)) {
            return TRUE;
        } else {
            $this->form_validation->set_message('authenticate', 'Login failed, please try again.');
        }
    }

Please note that:
Code:
$this->layout->view('session/login');
and
Code:
$this->output->redirect(self::SUCCESS_PAGE);
are custom libraries I've built so ignore them. Those work, just incase you guys reply saying it should be this->load->view.

Any help and guidance would be highly appreciated, I've been trying to figure this out for an hour and been struggling with the login system all afternoon so I'm resulting to posting here for some extra hints and help getting it working.


Regards,

Jamie
#2

[eluser]jedd[/eluser]
Hi Jamie,

A couple of suggestions, of varying worth Smile

Unless you have good reason, don't muck with the model names - that is, a) follow the CI standard of first letter only being upper case, underscores between words, etc, and b) don't rename them on the way in. I think that just adds to confusion when you're learning.

Move your 'check_exists()' function into the model - in fact, have a few primitive functions in your model for 'account_exists()' and 'account_locked()' and the like, and you can then either call them sequentially, or have an encompassing model method like 'can_log_in()' that calls those two and returns a simple boolean.

You might want to have these model methods fronted by some common, trivially tiny, functions in your MY_Controller - this seems to be the most common usage for extending the core Controller - having simple auth style checks. Often they involve a call to your model to do this kind of check, and then the setting of either some session data, or an attribute of MY_Controller proper, so you can later just check for the value of $this->is_logged_in. In the past I've kept this stuff in session data and copied it into a MY_Controller class variable - not sure on the performance differences between accessing both - but it means you can then get fancy with refreshing user rights every x minutes (some people get worried about rights only being refreshed on logout/login).

Also it's probably faster again to just use set your Session data with a user name once the user is logged in, rather than set a user name *and* a logged-in status. I mention this to save you some time tomorrow afternoon. Wink

Oh, finally, for security reasons it's usually good to not differentiate (at the browser) between a user account not existing, a wrong password, and a locked account.
#3

[eluser]JamieBarton[/eluser]
Hi thanks for your response, I've took the time before reply in trying to create some model functions. What I now need is some direction (perhaps seeing some examples - If you or anybody would be kind enough to take the time on a Sunday) on how to use these functions inside of the controller.

Users.php - Model
Code:
<?php

class User extends Model
{
    const USERS_TABLE    =    'users';
    
    function __construct()
    {
        parent::__construct();
    }
    
    function get_user_by_id($user_id)
    {
        $this->db->where('user_id', $user_id);
        return $this->db->get(self::USERS_TABLE);
    }
    
    function is_activated($user_id)
    {
        return $this->get_user_by_id($user_id)->row()->user_activated;
    }
    
    function has_family($user_id)
    {
        return $this->get_user_by_id($user_id)->row()->user_family_id;
    }
    
    function correct_credentials($username, $password)
    {
        $this->db->where('user_username', $username);
        $this->db->where('user_password', $password);
        $this->db->limit(1);
        return $this->db->get(self::USERS_TABLE)->num_rows();
    }
    
}

My database has defaults for the user_activated to 0 on insert, I'll update the row to equal 1 when they have gone through the activation process. Anyways, back on topic, hopefully I can get some direction of where to go and what to do.

Thanks again for your time guys. Much appreciated by a noob like myself.

Jamie
#4

[eluser]jedd[/eluser]
[quote author="Jamie B" date="1258936683"]
My database has defaults for the user_activated to 0 on insert, I'll update the row to equal 1 when they have gone through the activation process. Anyways, back on topic, hopefully I can get some direction of where to go and what to do.
[/quote]

Well, it looks like it's coming along nicely. I'd probably make a few small changes - is_ and has_ style functions should return BOOL only, I'd not put the word 'user' in a function that lived inside my User model as its location / your controller call provides sufficient context (eg. ->User->get_details_by_id()), I'd stick with parent::Model() in the constructor, I'd not bother abstracting the table name into a variable, and I'd do lots more error and return-value checking (is the user-id valid, were any rows returned at all, if not I'd return FALSE - which will have knock-on effects into is_activated() for example, and so on).

But what do you want to do next?
#5

[eluser]JamieBarton[/eluser]
I guess what I want to do is create a login form:

Which I have the view for. login.php
Code:
<h2>Login</h2>

&lt;?php echo validation_errors(); ?&gt;

&lt;?php echo form_open('/session/login'); ?&gt;

    &lt;input name="username" type="text" /&gt;&lt;br />
    &lt;input name="password" type="password" /&gt;&lt;br /><br />
    
    &lt;input type="submit" value="Login" /&gt;

&lt;?=form_close()?&gt;

When the form is submitted, what I wold like to do is:

When form is submitted:

Check first for empty fields, if they're not empty, then continue and check is the logged in user exists using the model I built 'correct_credentials', if it exists, then store the username and perhaps the user_id in the session. I want to use the user_id and store it in the session, saves me querying again I guess if I just want to put the user_id into a submit form that needs the user id of who is logged in. Possibly a logged_in = TRUE too? So I can lockdown controllers by a function in a library for authentication perhaps? Like:

Code:
function is_logged_in()
    {
        return $this->obj->session->userdata('logged_in');
    }

Then possibly in the auth library too have something like
Code:
function restrict()
    {
        if (!$this->logged_in()) redirect("session");
    }
which would be the first line in my controllers. Perhaps I could take it a step further and add in a message into the parameters, and that'll display when it has redirected.

Again, thank you jeed for your continued support with this. Highly appreciated!


Regards,

Jamie
#6

[eluser]jedd[/eluser]
I really like n0xie's way of doing this kind of check - read [url="/forums/viewthread/129558/"]this thread[/url] for more insight.

I don't actually do it that way - instead I set up my functions and stuff in MY_Controller, and then in each normal controller's constructor I'll check for is_logged_in(), and if they're not I'll redirect them to member/login. I have one controller where I need granularity finer than 'whole of controller' - and that's the member controller.

n0xie's approach is least-rights, mine is the inversion of that. (n0xie's is more sound, of course.)

[quote author="Jamie B" date="1258938874"]I guess what I want to do is create a login form:
Possibly a logged_in = TRUE too? So I can lockdown controllers by a function in a library for authentication perhaps? Like:
[/quote]

This is what I was talking about before - I'd suggest you avoid a logged_in variable, and rely on the presence of a session data for username (you unset this when running whatever logout() method you have). This isn't to say you shouldn't / couldn't use a is_logged_in() function in your MY_controller, for example, but chances are that it'd just be a front for a check of the session data - slightly less code to type, slightly easier to read in various contexts.

I'd certainly stick with session data until you decide you need to do user-auth type database lookups on every page load. (Bit messy, I think.)

Authentication beyond 'is logged in or not' becomes more complex, obviously. The simplest next step is a simple admin / normal user arrangement, in which case you might have an admin flag in session data too - set during authentication, pulled from the DB.

Security - look at using database sessions. Not essential to encrypt them at that point, I believe, but I encrypt mine out of habit.

You should checkout things like Bamboo Invoice, and the other big app published a little while ago - [url="/forums/viewthread/129017/"]unravel the music[/url] - as they have login code ready to go. There's also the [url="http://github.com/thody/User-Library"]User Library[/url] that thody set up a little while back - you might want to go back a few rev's on that, as I think the latter versions were a bit too abstracted, and sadly became trickier to understand and implement I suspect.
#7

[eluser]JamieBarton[/eluser]
Thanks Jedd,

As for your last few words in your post, I've already created a table for 'groups' so I sort of have in mind using user permissions. So you reckon it'll be best saving the user group in the session? The id / alias or call it everytime; sort of goes back to your previous comment on refreshing the session data; like a user is able to login, etc.

I'm thinking of having a banned group too, so I'd want to ban them instantly, not wait for them to logout and back in. So would I have a function in the library to grab the current user group id / alias?

I haven't worked with MY_controllers and fairly new with CI and PHP as you can probably tell from my questions on this forums so far.

Hopefully I'll be able to give all my code back to the community here when it is complete, as it's pretty very basic authentication system I hope when it's finished to implement further by users.

Also, just for clarity, how would you re-write the code I posted above:
Code:
function is_logged_in()
    {
        return $this->obj->session->userdata('logged_in') ?;
    }
    
    function get_username()
    {
        return $this->obj->session->userdata('username');
    }

    function restrict()
    {
        if (!$this->logged_in()) redirect("session");
    }

I'm thinking the obvious; if () { return true; } else { return false; }


Regards,

Jamie
#8

[eluser]jedd[/eluser]
[quote author="Jamie B" date="1258946166"]
As for your last few words in your post, I've already created a table for 'groups' so I sort of have in mind using user permissions. So you reckon it'll be best saving the user group in the session? The id / alias or call it everytime; sort of goes back to your previous comment on refreshing the session data; like a user is able to login, etc.
[/quote]

ACL (or anything more complex than guest (not auth'd), use (auth'd) and admin (auth with one flag)) can get pretty complex - and there's lots of ways to attack the problem. Hierarchical - where every access level is a superset of the one beneath. Or where every single thing you can do has its own flag or value. Or probably a few dozen other ways. I have no answers for you, as I'm still pondering how best to do this - but there's plenty of examples out on the intergoogle about this stuff.

Quote:I'm thinking of having a banned group too, so I'd want to ban them instantly, not wait for them to logout and back in. So would I have a function in the library to grab the current user group id / alias?

I see two ways (there may be more) to do this.

A) do a DB lookup on every page load, to check if banned, and if so drop the session for the user.
B) the function that does the banning skims through the ci_session table and deletes that user's session.

The latter is obviously a bit less load, but I'm not sure on the details / limitations / undocumented features of such an approach.

Quote:I haven't worked with MY_controllers and fairly new with CI and PHP as you can probably tell from my questions on this forums so far.

You gotta get yourself one - they're free, after all. Smile Check out my blurb [url="/wiki/Header_and_Footer_and_Menu_on_every_page_-_jedd/"]in the wiki[/url] on some of the things you can do with them. Plus I get 2c for every clickthrough.

Quote:Hopefully I'll be able to give all my code back to the community here when it is complete, as it's pretty very basic authentication system I hope when it's finished to implement further by users.

Not to detract from the goal - but there's already a heck of a lot of auth systems out there. Are you coding one because you don't know about [url="/wiki/Category:Contributions::Libraries::Authentication/"]the 20 or so[/url] in the wiki - or because none of them do precisely what you want (the usual reason for writing your own)?

As to your functions, I'd probably:
Code:
function is_logged_in()
    {
        return ( $this->obj->session->userdata('username')) ? TRUE : FALSE;
    }
    
function get_username()
    {
        return  ($this->obj->session->userdata('username')) ? $this->obj->session->userdata('username') : FALSE;
    }


The restrict function I use in the constructor of pretty much all my controllers is:
Code:
$this->_ensure_authenticated_user( "Forum" );
// 'Forum' is whatever string I want to appear in the later 'you've been redirected from ...' message

Check [url="/forums/viewthread/124509/#616091"]this thread[/url] for code showing how I do this in MY_Controller.
#9

[eluser]JamieBarton[/eluser]
Reason for writing my own because when a user signs into my site I want to grab some stuff from the database, such as an idea for a group they're part of. Group here probably being a bad word to use as I've used groups for permissions based, I'll attack that and change the name of the roles/permissions groups.

But the site will allow you to login;

Once you're logged in it'll grab the group ID you're assigned to, if you're not assigned a group I want to send the user to a page to join a group before continuing to use site features; therefor; you must be in a group (only one group) before you can continue to browse.

I want a auth system that I can use and later adapt and know the inside out workings of it, I recently tried Tank_Auth and FreakAuth, but they're too complex for what I want. I just want something I know the inside out of and possibly whenl ooking at the code know what something does instantly without having to read too much in-depth.

Thanks for your continued support, I'll read your posts and search these forums for any examples of basic authentication too.
#10

[eluser]JamieBarton[/eluser]
Here is what I had originally:

Code:
&lt;?php  
if (!defined('BASEPATH')) exit('No direct script access allowed');

class Auth
{
    
    var $obj;
    var $controller;
    
    function Auth($controller="session")
    {
        $this->obj =& get_instance();
        $this->controller = $controller;
        
        $this->obj->load->library('session');
    }
    
    function login()
    {
      $this->obj->session->set_userdata(array('logged_in' => true));
    }
    
    function logout()
    {
      $this->obj->session->unset_userdata('logged_in');
    }

    function logged_in()
    {
      return $this->obj->session->userdata('logged_in');
    }
    
    function restrict()
    {
      if (!$this->logged_in()) $this->obj->output->redirect("/$this->controller");
    }
}
?&gt;

Not sure if that would do the perfect job.




Theme © iAndrew 2016 - Forum software by © MyBB