Build a better Login with Adobe Flex, Zend_Amf, Zend_Auth, and Zend_Acl – On The Flex Side
Since Adobe announced that they were officially supporting Zend_Amf, developed by Wade Arnold, I thought it would behoove me to discover what this was all about, so I developed a simple Access control project to get familiar with the Zend Framework.
This example is a Flex 3 application developed using Cairngorm, Zend_Amf, Zend_Auth, and Zend_Acl to verify user accounts and permissions in a MySQL database.
The php code for this project is covered in the second half of this tutorial Build a better Login with Adobe Flex, Zend_Amf, Zend_Auth, and Zend_Acl - On The PHP Side
Zend_Auth has several adapters to authenticate with, there are adapters for OpenID, LDAP, text files, and databases. For this tutorial we will use the Zend_Db to authenticate the user against a MySQL database.
Zend _Acl is used to control the users access privileges.
With a few changes you could also use SQL Server, PostGreSQL , Oracle, or whatever your database setup happens to be. Also if you don't wish to use the MAMP structure you will have to modify the configuration to match your webserver setup. This tutorial is specific to MAMP on a local computer.
Please Note: This is an over simplified example and not meant to be a best Security practice.
This tutorial does not go into detail about the workings of the Cairngorm framework, if you need additional infomation about Cairngorm please consult the Cairngorm Docs.
Please consult the Zend Framework Reference Guide for more information about Zend_Amf, Zend_Auth and Zend_Acl.
This application is licensed under the

Build a better Login with Flex, Zend_Amf, Zend_Auth, and Zend_Acl by Keith Craigo is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License
You can view the completed application here, right click the application to view and download the Flex, SQL, and PHP source code
or can build as you go through this tutorial.
Okay let's get started:
Project Requirements:
- Flex Builder 3
or the Free Open Source Flex SDK - Cairngorm
- PHP 5 .2.8 , PHP 5.2.6
- MAMP - I use living e
- Zend Framework 1.7.1
Project Overview
Let's clear up some terminolgy first, Verification and Authorization are two totally different things.
Verification is the process of verifying that you are who you say you are.
Authorization is the process of determining what you have access to. What privileges are assigned to you.
Just because I can Verify I'm Keith doesn't mean I'm Authorized to view every area of a website.
Here's the basic workflow.

First screen of the application asks the user to login or go to the public screen, upon login submission there are 3 possible outcomes:
- The user is authorized and their access privileges will be retrieved based on their assigned user role Super, admin or manager. Their access privileges determine what they will see on the control panel.
- If either the username or password is incorrect the user will be presented with the message "Sorry! Either your username or password is incorrect, please try again or view the public site."
- The user is not authorized in which case they will default to the guest role and they are presented with the PublicView. The guest role only allows the user to view the PublicView.
Role Privileges:
| Role | Unique Privilege | Inherits |
|---|---|---|
| guest | View Public Pages | N/A |
| manager | Create Project, Assign Tasks | guest |
| admin | Create managers | manager |
| Super | View System Logs | N/A |
Setting up the Acl can become quite complicated but for now I'll try to keep it simple.
guest is the default role and is only allowed acces to the public area.
manager inherits all the privileges of guest plus this role is assigned some unique privileges shown in the table.
admin inherits all the privileges of guest and manager plus this role is assigned some unique privileges shown in the table.
Super is a special role, this role does not inherit from any other role but is given all privileges as well as some unique privileges as shown in the table above. I'll explain more in the server side code.
Initial Setup
Basic Directory Setup.
- Follow the Download and Install instructions of items 1 -4
- Download and unzip the Zend Framework 1.7.1 file to a location on your computer.
- Under your MAMP home directory and above the htdocs folder, create two new folders frameworks and utils.
Please note: it's a best practice to keep sensitive data such as database connection details out of the web root. - Copy the Zend Framework 1.7.1 /library/Zend folder to the new frameworks directory you just created.
Your directory structure should be similiar to:
MAMP/frameworks/Zend
MAMP/utils
Setup the MAMP MySQL database
Create a new database called AccessControlExample
Copy the following SQL into AccessControlExample
CREATE TABLE IF NOT EXISTS `admin` (`username` varchar(20)
NOT NULL,`password` varchar(20) NOT NULL,`realfirstName`
varchar(20) NOT NULL,`reallastName`
varchar(20) NOT NULL,`role` varchar(20)
NOT NULL,PRIMARY KEY (`username`))
ENGINE=InnoDB DEFAULT CHARSET=latin1;INSERT INTO `admin`
VALUES('admin', 'password','admin', 'admin', 'admin');INSERT INTO `admin`
VALUES('manager', 'password','manager', 'manager', 'manager');INSERT INTO `admin`
VALUES('Super', 'password','Super', 'Super', 'Super');
On The Flex Side
Setup your Flex Builder Project:
In Flex Builder create a new Flex project by either clicking File->New->Flex Project or
by clicking the arrow of the New Project button then select the Flex Project link as illustrated in the following image.

In the following dialog

for the project name type AccessControlExample
You can choose to accept the default location or supply a new location for the project.
Application type - Select Web application (runs in Flash Player)
Server technology - Application Server Type select PHP from the drop down.
Click next.

All of the above are fairly self explanatory. MAMP runs on port 8888.
Your configuration may be different depending on your particular Web Server.
After you click Validate Configuration and if all goes well, Select Next then Library path.

Here you can change the name of the main application file, I chose to leave the default.
Click Add SWC.
Provide the path to the Cairngorm.swc you downloaded previously.
Click Finish.
Configure the Compiler
Create a configuration file in your projects root directory, name the file services-config.xml, you can save this anywhere you like actually, you just have to provide the compiler the absolute path to it's location.
Copy and save the following xml into the services-config.xml file
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="amfphp-flashremoting-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="zend">
<channels>
<channel ref="my-zend"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition
id="my-zend"class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://localhost:8888/AccessControlExample/"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels></services-config>
Select Project->properties from the Main Flex builder menu.
In the left side menu select Flex Compiler as shown in the following image:

NOTE: this is how my configuration is setup, yours may be different depending on your locale.
In the additional compiler arguments after the -locale en_US,
Type -services services-config.xml
Click Apply if you wish to Apply the change and make any other changes
otherwise click OK to Apply the changes and close the dialog box.
Setup your project folders:
In the project src dir create the following structure:
- com/business
- In the com/business folder create the following 4 folders - commands, control, events, and delegates.
- com/vo
- com/views
- com/model
There are other layout configurations but I wanted to keep this as simple as possible for now. - Your folder structure should resemble the following,

In the business folder create a new MXML Component called Services.mxml , just accept the default settings for now, we will overwrite all the default code by copying, pasting and saving the following in the Services.mxml
<?xml version="1.0" encoding="utf-8"?>
<rds:ServiceLocator
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:rds="com.adobe.cairngorm.business.*"><mx:RemoteObject
id="LoginService"
destination="zend"
source="Login"showBusyCursor="true">
<mx:method name="verifyUser"/>
</mx:RemoteObject></rds:ServiceLocator>
Save and close this file, we won't need this anymore in this tutorial.
In the com/model folder create a new Actionscript class named ModelLocator.
Leave the Superclass empty, in the Interfaces section click the add button and select IModelLocator or just start typing IModel and then select com.adobe.cairngorm.model.IModelLocator.
You can accept the defaults for now.
after the declaration
package com.model
{
replace all the existing code with the following
import com.adobe.cairngorm.CairngormError;
import com.adobe.cairngorm.CairngormMessageCodes;
import com.adobe.cairngorm.model.IModelLocator;[Bindable]
public class ModelLocator implements IModelLocator {
// Single Instance of Our ModelLocator
private static var __instance:ModelLocator = null;public function ModelLocator(__enforcer:SingletonEnforcer) {
if (__enforcer == null) {
throw new CairngormError( CairngormMessageCodes.SINGLETON_EXCEPTION, "ModelLocator" );
}
}
// Returns the Single Instance
public static function getInstance() : ModelLocator {
if (__instance == null) {
__instance = new ModelLocator( new SingletonEnforcer );
}
return __instance;
}
//DEFINE YOUR VARIABLES HERE
public var workflowState:uint = LOGIN;
public var CURRENT_USER_ROLE:String="";
public var MAINNAV:ArrayCollection = new ArrayCollection();public var admingranted:Boolean = false;
public var supergranted:Boolean = false;// DEFINE VIEW CONSTANTS
public static const LOGIN:uint = 0;
public static const CONTROLPANEL:uint = 1;
public static const PUBLIC:uint = 2;}
// Utility Class to Deny Access to Constructor
class SingletonEnforcer {}
Here were setting up our default screen, the Login screen, in the workflowstate variable. A little later we will see how we can change this variable to control the different states of the application. You can close ModelLocator.as, we won't need to visit this code anymore.
In the com/views folder create the following MXML Components. Base all the components on Canvas.
Login.mxml, PublicView.mxml, and ControlPanel.mxml
In Login.mxml create a form with two textInput controls, give the first one an id of " txt_username" ,
for the second give it an id of "txt_password". The forms Formheading label="Please Login or you can click Public in the nav bar above if you don't have an account." You could setup a subscribe feature but that is beyond the scope of this tuturial.
Place a button on this form and give it an id of "btn_login" with the label "LOGIN" and pass the mouse click event to the function verifyUser(event) as shown in the following snippet.
Or you can just copy and paste the following code right after the <mx:Application> tag.
<mx:Script>
<![CDATA[
import com.model.ModelLocator;
import com.business.events.LoginEvent;
import flash.events.Event;
import com.vo.LoginVO;[Bindable] public var __model:ModelLocator = ModelLocator.getInstance();
public function verifyUser(e:MouseEvent):void {
var loginEvent:LoginEvent =new LoginEvent(new LoginVO(txt_username.text, txt_password.text));
loginEvent.dispatch(); } ]]>
</mx:Script>
<mx:Form horizontalCenter="0" verticalCenter="0">
<mx:FormHeading label="Please Login or you can click Public in the nav bar above if you don't have an account."/> <mx:FormItem label="User Name:" height="26">
<mx:TextInput id="txt_username"/>
</mx:FormItem>
<mx:FormItem label="Password:" height="26">
<mx:TextInput id="txt_password" displayAsPassword="true"/>
</mx:FormItem><mx:FormItem>
<mx:Button label="LOGIN" id="btn_login" click="verifyUser(event);"/>
</mx:FormItem>
</mx:Form>
Please note: Normally styling information such as fonts, colors etc... should be placed in a css file, but in my opinion
inline styles are fine for quick demo purposes.
Next in the PublicView.mxml , I'll keep this real simple, just place a single label in this file.
The label text should be "Welcome ! This is the public page."
In the ControlPanel.mxml, replace the code contents with the following
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
xmlns:mx="http://www.adobe.com/2006/mxml"
width="400" height="300"
creationComplete="init();"><mx:Script>
<![CDATA[
import com.model.ModelLocator;
[Bindable] public var __model:ModelLocator = ModelLocator.getInstance();/** Initializes the control panel by enablingUI elements based on the users access privilegesthat are set in the model.
* @param none
* @return void
* */
public function init():void {
// The userRole determines which
// buttons will be enabled or disabled
Admin.enabled = __model.admingranted;
Super.enabled = __model.supergranted; }]]>
</mx:Script><mx:VBox
fontFamily="Verdana"
horizontalAlign="center"
verticalAlign="middle"
fontSize="10"
color="#020202"
width="100%"
height="100%"
x="0" y="0">
<mx:Label text="Welcome! This is the Secure page." />
<mx:Label text="You are logged in with the User Role of"/>
<mx:Label text="{__model.CURRENT_USER_ROLE}"
fontFamily="Verdana"
fontSize="12"
fontWeight="bold"
color="#FC0202"/>
<mx:Button id="Admin"
label="Admin Functions"/>
<mx:Button id="Super"
label="Super Admin Functions"/>
<mx:Button id="btn_common"
label="Create Project"/>
<mx:Button id="btn_common0"
label="Assign Tasks"/></mx:VBox>
</mx:Canvas>
We now need to modify our main mxml file, AccessControlExample.mxml or whatever you saved the main file as.
Replace all the code in this file with the following
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"xmlns:views="com.views.*"
xmlns:business="com.business.*"
xmlns:control="com.business.control.*"
layout="absolute"
creationComplete="init();"
viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import com.model.ModelLocator;
[Bindable]public var __model:ModelLocator = ModelLocator.getInstance();
/** Initilizes the main menu
* @param none
* @return void
**/
public function init():void {
var mnuItems:Array = [{label: "Public"}];
__model.MAINNAV = new ArrayCollection(mnuItems);
}
/** Handles navigation when a user
* clicks a button in the main nav bar
* @param uint - Nav Bar Buttons SelectedIndex* @return String - returns the lable text associated
* with the SelectedIndex**/
public function handleMainNav(i:uint):void
{
switch(__model.MAINNAV.getItemAt(i).label)
{
case 'Control Panel':__model.workflowState = ModelLocator.CONTROLPANEL;
break;
default:__model.workflowState = ModelLocator.PUBLIC;
break;
}]]>
</mx:Script><!-- Cairngorm Mappings -->
<business:Services id="services" />
<control:Controller id="controller"/>
<mx:ViewStackid="userViews"
horizontalCenter="0"
verticalCenter="0"
selectedIndex="{__model.workflowState}">
<views:Login/>
<views:ControlPanel/>
<views:PublicView />
</mx:ViewStack>
<mx:ApplicationControlBar
y="100"
width="400"
height="36"
horizontalCenter="0">
<mx:MenuBar id="mainNav""
width="100%" height="100%"
dataProvider="{__model.MAINNAV}"
click="handleMainNav(mainNav.selectedIndex);" />
</mx:ApplicationControlBar>
</mx:Application>
Remember the verifyUser function in our Login.mxml file, we need to create a LoginEvent.as class now.
Right click com/business/events, select New->Actionscript class and name this new file LoginEvent.as .
Make sure the package is com.business.events
Set the Superclass to com.adobe.cairngorm.control.CairngormEvent
Click Finish
Replace the contents of this file with the following code
package com.business.events {
import com.adobe.cairngorm.control.CairngormEvent;
import com.vo.LoginVO;
import flash.events.Event;
public class LoginEvent extends CairngormEvent {
public static const LOGIN:String = "Login";
public var userVO:LoginVO;
public function LoginEvent(_userVO:LoginVO) {
super(LOGIN);
this.userVO = _userVO;
}
override public function clone():Event {
return new LoginEvent(userVO);
}
}
}
Create a new Actionscript class in com/vo. Name this file LoginVO.as
Click Finish
Replace the contents of this file with
package com.vo {
import com.adobe.cairngorm.vo.IValueObject;
[Bindable] [RemoteClass(alias="LoginVO")]
public class LoginVO implements IValueObject {
public var username:String;
public var password:String;public function LoginVO(_username:String,_password:String) {
this.username = _username;
this.password = _password;}
}
}
Save and close both LoginEvent.as and LoginVO.as
Create a new Actionscript class file in com/business/commands. Name the file LoginCommand.as
Replace the contents of LoginCommand.as with the following
package com.business.commands {
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import com.business.delegates.LoginDelegate;
import com.business.events.LoginEvent;
import com.model.ModelLocator;
import mx.controls.Alert;
import mx.rpc.IResponder;public class LoginCommand implements ICommand, IResponder {
public var __model:ModelLocator = ModelLocator.getInstance();public function LoginCommand() { }
public function execute(event:CairngormEvent):void {
var loginEvent:LoginEvent = event as LoginEvent;
var delegate:LoginDelegate = new LoginDelegate( this );
delegate.verifyUser(loginEvent.userVO);
}public function result(event:Object):void {
if(event.result) {
if(event.result == "FAILURE_CREDENTIAL_INVALID") {
mx.controls.Alert.show("Sorry! Either your User Name or your password are incorrect. Please try again or you can view the public page");
return;
}
var accessPrivs:Object = event.result;
if(accessPrivs["viewRestrictedUI"]=="allowed") {
// set default privileges
__model.supergranted = false;
__model.admingranted = false;
__model.MAINNAV.addItem({label: "Control Panel"});
__model.workflowState = ModelLocator.CONTROLPANEL;
__model.CURRENT_USER_ROLE = accessPrivs["userRole"];
if(__model.CURRENT_USER_ROLE == "Super") {
__model.supergranted = true;
__model.admingranted = true;
} else if(__model.CURRENT_USER_ROLE == "admin") {
__model.supergranted = false;
__model.admingranted = true;
}} else {
__model.workflowState = ModelLocator.PUBLIC;
}
// DEBUG MODE
trace("[User Login] - user Role:" +accessPrivs["userRole"]);
trace("[User Login] - viewPublicUI:" +accessPrivs["viewPublicUI"]);
trace("[User Login] - viewRestrictedUI:" +accessPrivs["viewRestrictedUI"]);
trace("[User Login] - createManager:" +accessPrivs["createManager"]);
trace("[User Login] - viewLogs:" +accessPrivs["viewLogs"]);
}
}public function fault(event:Object):void {
trace("[User Login] - Error Connecting!" + event.toString());
}}
}
Create a new Actionscript class file in com/business/delegates. Name the file LoginDelegate.as
Replace the contents of Logindelegate.as with the following
package com.business.delegates {
/*** LoginDelegate
* Passes the users credentials as a value object tothe service.
* */
public class LoginDelegate {
import mx.rpc.IResponder;
import com.vo.LoginVO;
import com.adobe.cairngorm.business.ServiceLocator;private var responder : IResponder;
private var service : Object;/**
* Initilizes the service call* @param IResponder responder
* @return nothing
* */
public function LoginDelegate( responder:IResponder ) {
this.responder = responder;
this.service = ServiceLocator.getInstance().getRemoteObject("LoginService");
}/**
* Command that actually calls the service and addsthe responder mapping to the service method call
* @param LoginVO login
* @return void
* */
public function verifyUser(login:LoginVO):void {
var call:Object = service.verifyUser( login );
call.addResponder( responder );
}}
}
Next we need to create the controller to map the LoginEvent to the LoginCommand.
In com/business/control create a new Actionscript class named Controller.as.
Replace the contents with the following.
package com.business.control {
import com.adobe.cairngorm.control.FrontController;
import com.business.commands.*;
import com.business.events.*;/**
* Controller
* Mappings of Cairngorm Events to Cairngorm commands
**/
public class Controller extends FrontController{
/**
* Class constructor
* @param none
**/
public function Controller() {this.initialize();
}/**
* Initializes the mappings
* @param none
* @return void
**/
public function initialize():void {
//ADD COMMANDS
this.addCommand(LoginEvent.LOGIN,LoginCommand);
}
}
}
Now on to the PHP code


February 12th, 2009 - 19:10
Hi Keith,
Thanks for these in depth articles as an intro to Zend auth. Very easy to follow.
However, I have a question regarding your preface note: “This is an over simplified example and not meant to be a best Security practice.”
Any chance you can elaborate on this? I’d like to know where the pitfalls might be.
cheers
February 12th, 2009 - 20:43
Hi Kevin,
I see your point but I just made that statement to let everyone know that I’m not a security expert by any means and that the article does not cover topics such as encryption methods for transferring sensitive information like user credentials, encrypting passwords in the database, using ssl, or making sure the data submitted is not tainted on the server side as well as on the client side. The article is really just a quick intro to get started using Zend_Auth.
Thank you for your input.
Keith
February 12th, 2009 - 21:11
Thanks for the response – I understand completely. It’s just sometimes hard to know why a caveat is stated for an example exercise and so creates some doubts about whether to use it.
If I could make a recommendation to you and all the other gurus out there who have the time and kind inclination to share these tidbits of info, please add a sentence at the end with some suggestions for extra work that you suggest would make the solution more enterprise ready.
Thanks again for your post.
cheers
March 2nd, 2009 - 16:28
Decent article, or well great, however I think it needs to cover one more essential topic. How to validate further calls to services? This just validates once, but how do you then check if a user is logged in from other services, in other class’s?
I read in the zend framework docs that you could do something like:
auth = Zend_Auth::getInstance();
}
public function testFunction() {
if ($this->auth->hasIdentity()) {
// Identity exists; get it
$identity = $auth->getIdentity();
return $identity;
}
}
}
But it always returns null even though I have made a succesfull login through the LoginManager class.
Any tips there?
Also, you should get a better code viewer plugin for wordpress.
March 3rd, 2009 - 10:58
Lasse,
Normally as long as the call is within the same browser session.
validation can be done by placing a call to getSessionID() and then comparing that id to the sessionid that was returned when the user first successfully logged in. As in my example you would use the Remote Object method, LoginService.getSessionID(); and compare the return value to __model.CURRENTSESSIONID
Referring to your code example, are you calling this function from within the same browser session? If so, there’s no need to get the Zend_Auth instance after successful login the instance was created when you first logged in. That is if your using the LoginManager class from my example. Then this code is trying to create a new and separate instance where identity is not established yet.
If your talking about validating from services outside of the current browser session such as from another browser or application then you may want to investigate setting up application ID’s like Google and Yahoo do but this is something that I haven’t researched yet so I can’t go into details about it.
Calls from outside services would be considered separate sessions with different sessionids assigned.
Hope this helps
Keith
March 4th, 2009 - 14:51
Hello Keith, thank you for your response.
This is the class where the testFunction was in:
auth = Zend_Auth::getInstance();
}
public function testFunction() {
if ($this->auth->hasIdentity()) {
// Identity exists; get it
$identity = $auth->getIdentity();
return $identity;
}
return false;
}
}
Know I read in the zend framework docs, that Zend_Auth by default creates a persistent storage of the currently logged in identity (if there is one), but I can’t seem to figure how to access outside of the LoginManager class.
Also I’d like to do the login validation serverside, so that public functions from the server can’t be invoked through a different flex app that would connect to the same bootstrap file, without being logged in.
/Lasse
March 4th, 2009 - 14:53
Alright so I can’t post the full php code in here it seems, This is the code: http://rafb.net/p/nMECVP42.html
March 6th, 2009 - 15:30
Here’s a way to validate in other class through persistent storage using sessions.
Inside of LoginManager in the switch handler handling the authenicate() result, do this:
case Zend_Auth_Result::SUCCESS:
// We need to return the authenticated users role, this will be passed into the Zend_Acl
// getResultRowObject returns a stdClass object so we need to dereference the role in this manner.
$r = $authAdapter->getResultRowObject(array(‘accessRole’));
$userRole = $r->accessRole;
$storage = $this->auth->getStorage();
$storage->write($authAdapter->getResultRowObject(array(
‘username’,
)));
break;
and add a private $auth variable..
Then when you want to validate (from anywhere) you just do this:
if ($this->auth->hasIdentity()) {
// Identity exists; get it
$identity = $this->auth->getIdentity();
return $identity;
}
Now only one problem left, in amfphp we had a beforeFilter where I would have normally put the code above, but since there’s no such thing in Zend_Amf the only solution seems to be throwing an error inside a class’ __constructor if validation fails.
But that returns an error like this:
[getOrdersCommand] – Error Connecting![FaultEvent fault=[RPC Fault faultString="Error instantiating class BackendManager to invoke method getProducts" faultCode="621" faultDetail="#0 /www/domain.com/store/library/Zend/Amf/Server.php(298): Zend_Amf_Server->_dispatch('getProducts', Array, 'BackendManager')
#1 //www/domain.com/store/library/Zend/Amf/Server.php(387): Zend_Amf_Server->_handle(Object(Zend_Amf_Request_Http))
#2 /www/domain.com/store/public/gateway.php(44): Zend_Amf_Server->handle()
#3 {main}"] messageId=”580746DF-8878-BB69-EB6E-000053C8378A” type=”fault” bubbles=false cancelable=true eventPhase=2]
However I read that by extending Zend_Controller_Action you can have a function called preDispatch() which works like amfphp’s beforeFilter, but I can’t seem to figure out how to properly extend it i.e. the preDispatch function is never called in my case.
If I could just find a way to validate before invoking the called method…
March 15th, 2009 - 16:50
Any thoughts on implementing a beforeFilter() function?
March 22nd, 2009 - 15:59
Lasse,
Sorry I haven’t had a lot time to research this yet.
April 17th, 2009 - 01:33
Wonderful article. I been looking for one on a similar note. I guess you always have something up your sleeve.
April 30th, 2009 - 09:38
Not to “rain” on your article, it seems well thought-out and the scriplets are very helpful, but question…..what exactly do you mean by this being a “better” login solution?
April 30th, 2009 - 20:02
Hi Nic,
It’s just my opinion, I’m not saying it’s the absolute best way to do this, it’s just that Flex and Zend work really well together for me.
July 1st, 2009 - 06:41
Hello Keith,
as discribed above, you are using mamp and php 5.2.8. How did you update php 5.2.6 within the mamp installation. Does your project only works with php 5.2.8?
July 1st, 2009 - 07:50
Holde,
Sorry I totally glossed over that typo.
I upgraded my Mac to 5.2.8 but not MAMP version of 5.2.6, I’ll correct that.
The example will work for 5.2.6.
I’m now using the Zend CE server.
But I was able to find this discussion on upgrading XAMPP, seems simple but I haven’t tried it yet.
http://www.retireat21.com/forums/design-development/1512-upgrading-php-version-xampp.html
Thank you
Keith
July 1st, 2009 - 11:29
Thank you for answering. I´ve tried to make newer example with sessionid´s work on my mac. First I thought it´s not working because of php 5.2.6 in mamp, but now with your answer that it will work for 5.2.6 the problem is anywhere else. When I hit the login button nothing happens, only the session has timed out. I´ve tried to follow your tutorial very strict. Any idea how to check and solve your example
July 1st, 2009 - 11:40
Holde,
Hopefully this may help,
Build a better Login with Adobe Flex, Zend_Amf, Zend_Auth, and Zend_Acl – Sessions
Keith
July 1st, 2009 - 11:49
Yes, this tutorial is the one I used. Firebug reports “500 Internal Server Error” for POST AccessControlExample
July 14th, 2009 - 01:21
Hi Keith,thanks for the tutor..I want to ask,i’v downloaded the code for the example also i’ve followed your instructions..When i try to login,it goes to your website..What should i change??Thanks…
July 14th, 2009 - 01:50
Sorry keith,i found out whats happening..I haven’t change endpoint-uri..Thanks…
July 14th, 2009 - 04:19
Sorry Keith,right now it just says connecting to localhost,when i try by click on the login button..Nothing happens…Thanks…
July 14th, 2009 - 08:16
Handoyo,
Off the top of my head, check that the database connection in the LoginManager.php is set to your database configuration.
Here’s the structure of the connection helper class that I use in the example.
class ExamplesConnectionHelper
{
public function __construct() {
$this->host=”;
$this->dbname=”;
$this->username =”;
$this->password = ”;
}
}
July 14th, 2009 - 12:54
I got this error message when i try to call direct to LoginManager.php
Warning: require_once(ConnectionHelper.php) [function.require-once]: failed to open stream: No such file or directory in C:\wamp\www\AccessControlExample\phplib\LoginManager.php on line 4
Fatal error: require_once() [function.require]: Failed opening required ‘ConnectionHelper.php’ (include_path=’.;C:\php5\pear’) in C:\wamp\www\AccessControlExample\phplib\LoginManager.php on line 4
July 14th, 2009 - 13:30
Handoyo,
I’ve provided the basic structure of the ConnectionHelper class in my previous reply, this is usually handled by the developer since each database and connection scheme can be different depending on your database server. That’s why I didn’t include it as part of the initial downloads.
Hope that helps
Keith
July 14th, 2009 - 20:54
Ok Keith,i’ll try it out..I’ve configured the connection helper according to my database server..But i will tell you if i got it working out. the way it should be..Thanks a lot…..
September 8th, 2009 - 14:38
Just wanted to thank you for the work you put into this post and for sharing the information. I learned a great deal!
sd
September 8th, 2009 - 20:31
Your welcome.
October 4th, 2009 - 04:30
I just wanted to say thanks as well. This was very helpful.
October 4th, 2009 - 08:45
Otto,
Your welcome.
November 30th, 2009 - 13:41
Hi, I had a strange error message from FLEX 3 bulider:
A file found in a source-path can not have more than one externally visible definition in the ModelLocator.as. I think it’s because of two classes are declared in one package. OF course it can’t compile and nothing show up.
I’m new to flex and as any hints?
r. Sandor
November 30th, 2009 - 21:16
Hi Sandor,
Question are you getting this error from my code?
This usually means what you stated in your post about 2 classes in one package.
This great post may help clarify
Take a look at http://www.actionscripterrors.com/?p=2017
December 1st, 2009 - 11:39
Hi Keith,
It was definitely your code that was wrong I commented out the SingletonEnforcer references in the ModelLocator.as file and the error is gone. Everything works fine since them apart from some visual glitches
r. Sandor
February 26th, 2010 - 13:29
Excellent article.. have been searching for hours and this is exactly what I’ve been looking for! Thanks very very much!
March 3rd, 2010 - 23:26
Thank you, I’m glad it was helpful
Keith