Heres a great tip and trick that allows you to autologin a user without storing their username or password AND also enforce Rolling permissions (only one login per user account at a given time).
For greater clarity:
Autologin= User information automatically saved upon a login that allows him/her to return to your app without ever having to see the login screen again. All of this _without_having to check the "remember password" button that is provided by PHPRunner by default.
Rolling Permissions = User "John" logs into web app on browser "A", if someone else uses "John" login information to access his account from browser "B" they will take control of the session and person on browser "A" will be logged off of the web app. This causes only one person to be logged in at a time per user account. I've also heard this referred to as a "free floating license" model.
Let's get started:
Step 1:
Make sure you create a column in your users table(I'm using MySQL) named "Session_ID" (CHAR 32).
After successful login
//After successfully logging in set the Session_ID in the users table where it matches the user who successfully logged in.
//This code also creates the cookie with that Session_ID
//This page is in effect bypassed by virtue of the code in "Login Page: Before Process" when there is a cookie already set (this page never even loads).
Global $conn;
$strUpdate = "
UPDATE
users_tbl
SET
Session_ID = '". session_id() . "'
WHERE
User_ID =" . $data["User_ID"];
CustomQuery($strUpdate);
$_SESSION["User_ID"] = $data["User_ID"]; //Notice that PHPRunner uses UserID "CamelCase" approach instead of what I used here "Underscore" approach to naming columns/fields
$_SESSION["Group_ID"] = $data["Group_ID"];//Same notice as previous line
$_SESSION["CurrentSession"] = session_id();
setcookie("Bluekey",$_SESSION["CurrentSession"],time()+3600); //set the cookie expiration to whatever time suits your needs. Name your cookie whatever you want... I named mine "Bluekey"
Step 2:
Login Page: Before process
//If there is a cookie then proceed with this code to check if the cookie session_id matches any records in the users table
if(@$_COOKIE["Bluekey"])
{
//Fetch the $data["User_ID"] from users table by matching the cookie value
global $conn;
$sql = "SELECT * FROM users_tbl where Session_ID = '".$_COOKIE["Bluekey"]."'";
$rs = db_query($sql,$conn);
$data = db_fetch_array($rs);
//Now we check if the Session_ID matches the cookie value.
//If you don't include this IF statement inside the main IF statement (first line of step 2) it would throw your application into a
//never-ending loop between the menu.php and login.php page... your browser would quickly throw a too many redirects error message!
if ($data["Session_ID"] == $_COOKIE["Bluekey"])
{
//Set the session variable based on the user_id retrieved from the dataset.
$_SESSION["User_ID"] = $data["User_ID"];
//This was a VERY IMPORTANT line of code to include because without it Firefox was going into a loop whenever you tried accessing it after logging, then closing browser, then accessing login page again.
//The browser was hittin login.php then going to menu.php, then looping back to menu.php because "menu.php" has a built-in line #8 that tells it to go back to login if not UserID is set... and since we don't set user ID when accessing this login page this way (the second time by relying on cookie) it needs to be set here!
$_SESSION["UserID"] = $data["User_Login"];
$_SESSION["GroupID"] = $data["Group_ID"];
//Bypass the login screen and take directly to menu screen.
header("Location: menu.php");
exit();
}
}
Step 3:
In each of your tables shown in the "events" tab of PHPRunner make sure you add this to the "After Table Intialized" event.
//If there is a cookie we will now check that cookie value against the users table to ensure its valid and active.
if(@$_COOKIE["Bluekey"])
{
//Fetch the $data["User_ID"] from users table by matching the cookie value
//If no cookie is found return false and stop processing any additional code on this page.
global $conn;
$sql = "SELECT * FROM users_tbl where Session_ID = '".$_COOKIE["Bluekey"]."'";
$rs = db_query($sql,$conn);
$data = db_fetch_array($rs);
//Set the session_id variable based on the user_id retrieved from the dataset so it can be used later in this script on this page.
$_SESSION["User_ID"] = $data["User_ID"];
$_SESSION["Group_ID"] = $data["Group_ID"]
}
else
{
return false;
};
Step 3 Correction: Update on Nov 12, 2010
I rewrote the script in step 3 because I noticed I was not getting the desired rolling login to occur depending on certain sequence of logging into and out my app from different clients. Thus, here's an update to step 3 (I'm intentionally leaving the previous code here in case you need to reference it if you've already used it). Plus, this adds one extra small layer of security that prevents cookies from being spoofed.
//If there is a cookie then check that cookie value against the users table to ensure its valid and active.
if($_COOKIE["Bluekey"])
{
//Fetch the $data["User_ID"] from msd_users_qry by matching the cookie value
//If no cookie is found return false and stop processing any additional code on this page.
global $conn;
$sql = "SELECT * FROM users_tbl where Session_ID = '".$_COOKIE["Bluekey"]."'";
$rs = db_query($sql,$conn);
$data = db_fetch_array($rs);
//Now we check the current client's session_id against the record retrieved from the db.
//If the Bluekey value in the client browser is different the $sql above would not retrieve anything and would thus not match anything against the session_id.
//We could have opted to compare the $data["Session_ID"] to $_COOKIE["Bluekey"] instead of comparing it to session_id()... however, by us comparing to session_id() it adds an extra layer of security!
//The extra layer occurs because even if someone were to manually/articially create a cookie called "Bluekey" on their browser and set the correct value that is store in the db their login attempt would still fail...
//...because we now instead compare the retrieved value against the server generated sesison_id for he browser client!
if ($data["Session_ID"] != session_id())
{
session_unset();
setcookie("Bluekey","",time()-365*1440*60);
header("Location: login.php");
exit();
}
}
else
{
return false;
};
TIP: In my app I changed the $sql select query to include a "active = 1" in the where statement. This way, if a user is made inactive in my backend table it automatically invalidates them regardless of cookie and session_id values. Note that I did not reflect those changes in the examples given here.
Step 4:
Modify the "login.php" page in your project output folder
//Insert this right after line #18 (assuming PHPR V5.2 build 5482)
//We need to destroy the cookie when user clicks on logout link
setcookie("Bluekey","",time()-365*1440*60);
//Remember this page will be reset every time you rebuild the project, so be careful
Step 5:
This is optional, but I would also add a layer of security by requiring that users enter their existing password if they decide to change/edit their own passwords on their account after logging in. The reason is that if an intruder were able to access a legitimate user account by spoofing the "Bluekey" cookie value (assuming that session value was still valid anyhow - notice this is one of the beauties in my approach... the validity of cookies is always reset whenever a user accesses he account... this offers greater protection and security) they would then be able to change the password of the legitimate user which would result in locking out that user and a hijacking of that account. This way, even if someone gains access to your account they won't be able to change your password... and to regain access all the legitimate user needs to do is login again.... and this causes the cookie used by the hijacker to no longer be valid!
I believe this approach offers a very secure method for allowing autologins and enforcing licensing terms on user accounts. It requires no encryption since all we are using is the session id value that is being stored in the database instead of adding cookies that store username and passwords (which would require encryption if you want it to be secure).
Best,