Authentication

Like the ColdFusion CFC functions, AMFPHP allows the optional “roles” attribute in the methodTable which you can use to limit access to specific functions. It also provides the Authenticate class which provides several helper methods for authentication purposes. Here is a typical example of how you would implement this:

<?php
class SendObject
{
    function SendObject()
    {
        $this->methodTable = array(
 
            "getPerson" => array(
                "description" => "Describe here your method",
                "access" => "remote",
                "roles" => "admin"   // this method will be available only if authenticate method returns "admin"
            ),
 
            "doLogin" => array(
                "description" => "Describe here your method",
                "access" => "remote",
                "roles" => "admin"   // this method will be available only if authenticate method returns "admin"
            )
        );
    }
 
    function getPerson()
    {
        $person = array();
        $person['first_name'] = "Alessandro";
        $person['last_name']  = "Crugnola";
        return $person;
    }
    
    function doLogin()
    {
        return true;
    }
 
    // This function will authenticate the client
    // before return the value of method call
    function _authenticate($user, $pass){
        if($user == "admin" && $pass == "secret"){
            return "admin";
        } else {
            return false;
        }
    }
}
?>

_authenticate is the standard name for the function that authenticates and determines roles. AMFPHP automagically calls it for you whenever it receives a setCredentials header from Flash.

Here, if the user has sent the right authentication info, the _authenticate returns the 'admin' string. From that point on, the user will have an 'admin' role. Thus it will have access to all unprotected functions as well as to all the methods which have a corresponding 'roles' attribute in the methodTable set to 'admin', as shown above. Multiple roles per user are also supported, see the section below for details.

Now, in the Flash code you need to use setCredentials method in order to have access to the getPerson remote method, in this way:

import mx.remoting.*;
import mx.remoting.debug.NetDebug; // load the debugging classes
NetDebug.initialize(); // initialize the NetConectionDebugger!
 
function handleResult( data ){
  // implement onresult here
}
function handleStatus( data ) {
  // implement error handling
}
var serv:Service = new Service("http://localhost/flashservices/gateway.php", null, "SendObject", null, null);
serv.connection.setCredentials("admin", "secret");
var pc:PendingCall = serv.getPerson();
pc.responder = new RelayResponder(this, "handleResult", "handleStatus");

Or in ActionScript 1:

   #include "NetServices.as"
   #include "NetDebug.as"
   
   mainResponder = new Object();
   mainResponder.onResult = function( data ){
     // implement onresult here
   }
   mainResponder.onStatus = function ( data ) {
     // implement error handling
   }
   NetServices.setDefaultGatewayUrl("http://localhost/flashservices/gateway.php");
   conn = NetServices.createGatewayConnection();
   serv = conn.getService("SendObject", mainResponder);
   // send the credentials request header
   conn.setCredentials("admin", "secret");
   serv.getPerson();

If you don’t send setCredentials method or use invalid user/password, amfphp will generate an error, and onFault will be triggered.

Catching authentication errors

One way of catching authentication errors is using a helper method. In the above class, the doLogin method is used as a helper. You call this method from the client side after setting credentials, but before calling the secured method. In this way, if you get an error because of invalid credentials, your responder will branch out differently and you can correctly handle unidentified users.

By using doLogin_onStatus or doLogin_onResult you can forward the user to the appropriate screen in your movie, or ask him to re-enter the credentials.

Here is another example, this time in AS2:

 
import mx.remoting.debug.NetDebug;
import mx.remoting.Service;
import mx.rpc.FaultEvent;
import mx.remoting.PendingCall;
import mx.rpc.ResultEvent;
import mx.rpc.RelayResponder;
 
import mx.controls.Alert;
 
class HostForm
{
	private var _gateway_url:String;
	private var _service_url:String;
	private var _service:Service;
	private var _pc:PendingCall;
 
	function HostForm()
	{
		_gateway_url = "http://localhost/flashservices/gateway.php";
		_service_url = "SendObject";
		_service = new Service(_gateway_url,null,_service_url,  null, null);
		_service.connection.setCredentials("admin", "secret"); 
		// calling the server side method to see if we are really ok with our credentials
		_pc = _service.doLogin();
		// A TIP ! - here you would show a nifty undetermined progress bar
		// and you would also block the user from input
		// both of this tips should be reverted when login gets result.
		_pc.responder = new RelayResponder(this , "doLogin_Result", "doLogin_Fault");
	}
	
	function getPerson():Void
	{
        	Alert.show("You now have access to the next action...", "Permision OK");
		_pc = _service.getPerson();
		_pc.responder = new RelayResponder(this , "getPerson_Result", "getPerson_Fault");
    	}
 
	private function getPerson_Result(re:ResultEvent):Void
	{
        	Alert.show(re.result, "Result got");
    	}
 
	private function getPerson_Fault(fe:FaultEvent):Void
	{
        	Alert.show("Code : "+fe.fault.faultcode + "  " + fe.fault.faultstring, "Service fault");
    	}
 
	private function doLogin_Result(re:ResultEvent):Void
	{
        	if(re.result)
        	{
        		// normally here you would show your users another screen with actions that they are allowed to do.
        		// in our case we just call the next method on the server side
        		getPerson();
        	}
        	else Alert.show("Invalid credentials", "Error");
    	}
 
	private function doLogin_Fault(fe:FaultEvent):Void
	{
        	Alert.show("Code : "+fe.fault.faultcode + "  " + fe.fault.faultstring + "Service fault");
    	}
 
}

Security tips

Remember that you should never include a user and password as plain text in Actionscript, as anyone with an actionscript decompiler can see it. Rather, collect the info from two textfields, and then set credentials.

SetCredentials works by sending the username and password in an AMF header. AMFPHP clears the sensitive information by asking the client to reset the authentication header to a special flag. Thus the info is sent on the next remoting call only. Thereafter, credentials are remembered using PHP sessions. This does not require cookies as the appends the session id to the gateway url.

Never send sensitive information unencrypted. Information like credit card numbers should only be sent through SSL. You can md5 sensitive passwords before sending them if you can’t use SSL.

If you need to logout your users, you can create a logout method in your class and call it from Flash:

function logout()
{
    Authenticate::logout();
    return true;
}

Authenticate is a class with the static logout method that can be used by any service in the framework; it is already included in your class’ namespace.

Multiple roles

The “roles” attrbitue can be a comma-separated list of valid roles, and your _authenticate function can also return a comma-separated list of list for the current user, meaning authentication is robust enough to accomodate a multiple-level logging and authorizing mechanism.


© amfphp.org | Disclaimer | Conditions of use