Flex and PHP: Authentication With an HTML Login Page

One of the first things to think about when building a Flex application is how you’re going to do authentication. Most people seem to include a username and password box in Flex and then make an HTTPService or AMF call to pass the authentication credentials. But I hate that solution. Most major browsers now have support to save usernames and passwords with autocomplete and that’s become something people expect from their logins. I think it’s also important to be able to clear the “remember me” cookie just like any other cookie as opposed to having it saved in a Flash cookie. Whenever you can provide the behavior people expect from their browser, you should.

So in this example I’m going to show how you might implement an HTML form with PHP for a Flex application. As I’m new to PHP there may be some bad practices here but I’ll update the post as I get feedback.

Creating the login page in PHP and HTML

To start, we can just use PHP’s built in session functions to create the session variables and build the login page called login.php. You start off by creating a session with session_start() and then you set some session variables to their defaults. Then you’ll show the username and password fields only if the form hasn’t been submitted and use the $_SESSION variables to store the information from the user. Finally, when everything is authenticated you use the header() function to send the user to the Flex application.

<?php
session_start();
$_SESSION['logged_in'] = false;
$_SESSION['username'] = "";
 
if(isset($_POST['is_submitted']))
{
$username = $_POST['username'];
$password = $_POST['password'];
 
// If the "Remember my username" box is checked
// then we use the setcookie function to save it.
// Otherwise, we clear it out. 
if($_POST['keep_username'] == true)
{
setcookie("username",$username,time()+36000);
} else {
setcookie("username");
}
 
// This is where you would look up the username
// and password. Normally this would be an LDAP call
// or a query to a database. In this case, I'm just
// accepting everything.
if($username && $password)
{
// Set our session variables.
$_SESSION['logged_in'] = true;
$_SESSION['username'] = $username;
 
// Redirect to the Flex application
header("location:flex/index.php");
} else
{
echo "Go back and put in a username and password.";
}
} else {
?>
 
<form name="login" action="<?php$_SERVER['PHP_SELF'] ?>" method="post">
Username: <input type="text" name="username" value="<?php echo $_COOKIE['username']; ?>" /><br/>
Password: <input type="password" name="password" /><br/>
Remember my username: <input type="checkbox" name="keep_username" value="true"><br/>
<input type="hidden" name="is_submitted" value="true" />
<input type="submit" value="Submit" />
</form>
 
<?php
}
?>

Notice the keep_username checkbox above. If the user checks that, you use the setcookie() method to create a cookie that will store the username on the next visit. If it is unchecked, the username will be blank.

Setting up the Flex Project

Even though most Flex applications take up the entire page, nearly all of the time you embed the actual SWF file on an HTML page. In Flash Builder when you create a new Flex application in creates the SWF files and the HTML files for you that embed your application. To do that it uses a template file that you can find in the html-template folder of your project. If you haven’t done so yet, go ahead and create a new Flex project. Use the defaults (do not use PHP as the server, leave it at None/Other). When you get to the second screen, set the output folder to a subdirectory named “flex” in the directory where your login.php file is located.

With the project created the first thing you’ll want to do is edit the template file. Go into the html-template directory and rename index.template.html to index.template.php. That will let you run PHP code inside of the template file. Flash Builder will automatically create an index.php file in the flex folder you specified in the create project wizard. Next you need to make sure your application will use the right file when you run or debug it. Right click on your project, select properties, and then select Run/Debug Settings. Now select your project in that box and click the “Edit” button. On the next screen, uncheck “Use default” in lowest box and put in the path to your application. You can see mine below (I’ve got http://localhost:8888 mapped to http://rainier.cascade.mtn but your local PHP server will probably use http://localhost).

Modifying the Index Template

Next you need to edit the template we just renamed. Open it up in Flash Builder (or your favorite text editor) and you should see a bunch of HTML. At the very top of that page you’re going to add some PHP code. First, you are going to check for a url parameter of logout to be passed. If it is, you destroy the session and log the user out. If that isn’t passed, you’re going to use the session information from your login page and save that information to variables on this page. This code goes at the very top before all of the HTML in your template page.

<?php
// Always start the session first.
session_start();
 
// You will also use this page to log out. If 
// ?logout=1 is passed in the URL, destroy the 
// session and log the user out.
if(isset($_GET['logout']))
{
if($_GET['logout'] == 1)
{
$params = session_get_cookie_params();
setcookie(session_name(),"", time()-3600,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]);
session_unset();
session_destroy();
}
}
 
// Create the default values for our session.    
$session_id = "";
$logged_in = false;
$username = "";
 
// If the session is valid, replace the default
// values with our session values.
if($_SESSION['logged_in'] == true)
{
$logged_in = true;
$session_id = $_COOKIE['PHPSESSID'];
$username = $_SESSION['username'];
?>

Now that your variables are set, you’ll send those to the Flash Player. There are a number of ways to get data into your Flex application but the most straight forward is to use a concept referred to as “flashvars”. Flashvars are parameters you can put within the embed code that will then be accessible by the Flex application. Flashvars are a great way to take a dynamic site, like one written in PHP, and change the behavior of a Flex or Flash application based on that dynamic PHP data. Look for the JavaScript in the template that includes var flashvars = {} and replace it with this code.

var flashvars = {session_id:"<?php echo $session_id; ?>",
logged_in:"<?php echo $logged_in; ?>",
username:"<?php echo $username; ?>"};

That code will make those three variables available to your Flex application. That way before you let the user do anything in your Flex application you can check to make sure the user is logged in correctly.

Finally, at the end of the template you’ll add some code to show the user an error message if they try to access the page without logging in.

<?php
} else {
echo "Not authorized, go back and log in.";
}
?>

Creating the Flex Application

In this example you’ll just create a very, very basic Flex application with two states, a beginning state and a logged in state. When the application loads, check the flashvars you added to the embed code and then change to the logged in state. In the logged in state also contains a button that uses the logout functionality you added to the template code. Here’s the whole Flex application.

<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600" currentState="startingScreen"
creationComplete="application1_creationCompleteHandler(event)">
 
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
 
protected function btn_clickHandler(event:MouseEvent):void
{
navigateToURL( new URLRequest( encodeURI("index.php?logout=1")), "_self");
}
 
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
if(this.parameters.logged_in == 1)
{
currentState = 'loggedIn';
}
}
 
]]>
</fx:Script>
 
<fx:Declarations>
<s:State name="startingScreen" />
<s:State name="loggedIn" />
</fx:Declarations>
 
<s:Panel name="Test" left="25" right="25" top="20"
bottom="25" title="My Application">
<s:Button id="btn" left="10" top="10"
click="btn_clickHandler(event)"
label="Log Out" includeIn="loggedIn" />
<s:Label id="lbl" left="10" top="10"
text="You need to log in"
includeIn="startingScreen" />
</s:Panel>
 
</s:Application>

Conclusion and Warnings

There are a couple of notes and warnings about this method. By using two states and checking the login parameters you aren’t just depending on the embed code. That means if someone browses right to the SWF file they won’t be able to access the application because it won’t move to the next state unless it gets those parameters. That’s also part of the problem in this very simple application.

In the Flex code that changes the state I just check to see if the flashvar logged_in is set to 1. If you were to download a local version of the PHP file as well as the SWF and change that embed code you’d have access to the application. In a more robust example you would want to add a couple of hooks into the database. One way to do that would be to store the session id and the username in the database in the login.php file. Then when your Flex application loaded you could make a call to another PHP page and pass the session id and username parameters to a function which would compare it to the session and username that were stored during login to make sure it matches up.

You might also want to implement a token system with a shared secret which is a good way to authenticate against external APIs, the kind that you would create in PHP and consume in a Flex application using AMF or REST.

So keep in mind that this isn’t ready for production. But hopefully it gets you started in the right direction when creating a PHP/Flex application that is going to use an HTML login form. The fewer Flex/Flash login forms there are the better.

Show Comments

Hide Comments

Comments are closed.