OwlManAtt (owner)

Revisions

gist: 117819 Download_button fork
public
Public Clone URL: git://gist.github.com/117819.git
Embed All Files: show embed
kitto-auth-info.markdown #

Registration / Login - Implementation in the KKK

This guide will give its reader an in-depth look at how KittoKittoKitto implements its registration/authentication system. Special attention will be paid to how the user's password is stored and communicated from the client to the server.

For more background on the architecture of Kitto, see the developer guide maintained by the ModularGaming project.

Database Schema

The first thing we will need is a database table to hold our user in. The following user table will be used for the remainder of this guide. It is the Kitto user table with all fields unrelated to this tutorial removed.

CREATE TABLE `user` (
  -- User & password.
  `user_id` int(11) NOT NULL auto_increment,
  `user_name` varchar(25) NOT NULL,
  `password_hash` char(32) default NULL,
  `password_hash_salt` char(32) NOT NULL,

  -- Used for managing logins
  `current_salt` char(32) NOT NULL,
  `current_salt_expiration` datetime NOT NULL,

  -- Profile information
  `datetime_created` datetime default NULL,
  `email` text NOT NULL,
  `age` smallint(3) unsigned NOT NULL,
  `gender` enum('male','female') NOT NULL,
  `profile` text NOT NULL,
  `signature` text NOT NULL,

  -- Other useful information.
  `registered_ip_addr` varchar(16) default NULL,
  `last_ip_addr` varchar(16) default NULL,
  `last_activity` datetime default NULL,

  -- Password reset stuff.
  `password_reset_requested` datetime NOT NULL,
  `password_reset_confirm` varchar(32) NOT NULL,

  PRIMARY KEY  (`user_id`),
  UNIQUE KEY `user_name` (`user_name`)
);

Registration - Frontend

We will need a way to get new users in to the user table. This is achieved via the registration process. Our register page has several components: an HTML form that users fill out, bits of Javascript that assist the user in filling the form out correctly, a PHP script that validates the form, and more PHP that stores the user data in the database.

We will begin with a look at our HTML form. The first line of interest is the form tag - it tells the user's browser where to send the form data (action) and using what HTTP method (method).

<form action='{$display_settings.public_dir}/{$self.slug}' method='post'>

The variables in the 'action' attribute form a URL. Kitto makes the base URL (example, http://my-pet-game.com) available as '$display_settings.public_dir'. 'self.slug' is the "file" for the current page - in this case, the action attribute would end up set to http://my-pet-game.com/register.

We have two choices for our method attribute - GET and POST. As per the HTTP standard, POST is supposed to be used when it causes something to change inside of your application. GET is supposed to be used for retrieving files; GET requests should not cause your application to change.

Since registration will result in a new user row being created, POST is the correct method for us to use.

We have this hidden form variable next:

<input type='hidden' name='state' value='process' />

Since we are submitting the form back to the same URL that the user accesses the form at (http://my-pet-game.com/register), this state variable will tell the PHP script that it's time to process the registration instead of showing the user a form. We'll see this in action later.

The rest of the form is contained inside of a table. Each row has a field label, and then a field. Here is the general structure of one of the rows:

<td>
    <label for='username'>User Name</label>
</td>
<td id='username_td'>
    <input type='text' name='user[user_name]' id='username' value='' maxlength='25' />
    <span class='textfieldRequiredMsg valid'>You must pick a username.</span>
</td>

The label tag's for attribute matches the id attribute on its form field. The user's browser can use this; most browsers will put your keyboard cursor in the form field if you click on the label.

The id attribute on the second table cell (username_td) is needed by the Javascript form validation. Kitto uses a library called Spry for this - it will highlight your form fields in red if the user has done something invalid. It will also show an error message - the span tag around the text "You must pick a username" will be hidden unless the user forgets to fill the field in.

We have several more fields. Some considerations:

  • The password field is present twice. Having the user enter their desired password twice ensures that they have not mis-typed it the first time and are locked out of their account before they even finish signing up.
  • The email field is only present once. Kitto does not send an activation email to the user. An activation email is used to ensure that the user has entered a valid address; I have not ever cared if the email address provided is valid. It is only used for password recovery. If a user decides that this functionality is not worth the risk of having their email address sold to spam lists, so be it. If you would like to send a validation email, you would want to ask for the address to be entered twice to ensure they have not typo'd it and locked themselves out.
  • The CAPTCHA code field. There is an image with a code displayed instead of a label. The purpose of the CAPTCHA image is to prevent automated scripts from creating users - in theory, only a real human being will be able to determine the correct code from the image. This style of CAPTCHA is not completely bullet-proof, but it does significantly deter spam bots.

The image is included in our form with a bit of Javascript. The a tag around the image creates a link. If you click on the link, a new image will be loaded (and some things updated on the back-end). The random number at the end of the URL is to prevent a browser from caching the image - it looks like a new URL to the browser, so the image will not be sought in the browser cache.

   <a href="#" onclick="javascript:document.getElementById('captchaimage').src = '{$display_settings.public_dir}/captcha.php?' + Math.random();return false;">
       <img id="captchaimage" src="{$display_settings.public_dir}/captcha.php" alt="CAPTCHA image" style='border: 0;' />
   </a>

Let us take a moment to look at the source code for the CAPTCHA generator. This script does two things:

  1. It comes up with a code and stores the code in a session variable. Sessions are tied to a user's browser by a cookie with a session ID. The actual data in the session is stored on the server.
  2. It puts the code in to an image, along with some other random lines/colours.

Later on, when are are validating the registration form, we can look at the data in this user's session and make sure that the code they typed in matches the code that the script generated.

Switching back to our form HTML - at the very bottom, we have a block of Javascript. There are a number of Spry.Widget.ValidationSomethingOrOther() lines, each defining the rules for valid/invalid data in the form field. We also define a Javascript function to check the two password form fields and ensure that what the user entered in each matches.

Registration - Backend

When the user has submitted the form, this PHP script validates it, and if the data is all OK, creates the user.