0
votes

I have a web application developed using flex and cakephp. My client need to make a desktop application of that web application using Adobe Air. The conversion of the flex to Air is done successfully. I the flex application the communication of flex and cakephp is handled using a remotes controller.

In air application I have a problem of authenticating the user with cakephp default user authentication. Can anyone help me to find a solution for this?

2
Please be more specific with the problems you are encountering. What have you tried so far? Are you sending a POST request and getting back JSON, for example?swiecki
Since cakephp has its own method of handling user login I want to know how can I handle it using airuser1120633

2 Answers

0
votes

i suggest you to send your user credentials via POST to your cakephp backend.

A login function in your UsersController would look something like this:

public function login() {
    if ($this->Auth->login()) {
    $this->serviceResponse(Status::SUCCESS);
} else {
    $this->serviceResponse(Status::AUTH_FAILED);
    }
}

// this is just an example out of my appcontroller to send json responses
public function serviceResponse($code, $data = array()) {
    $response = compact('code', 'data');
    $this->response->body(json_encode($response));
    $this->response->send();
    $this->shutdownProcess();
    exit;
}

// I also defined a class for return statuses
class Status {
    const SUCCESS = 'success';
    const ERROR = 'error';
    ...
}
0
votes

Basically, you want to send the validation request as an ajax request. To do that you need to modify headers, capture session ids through cookies and post them to keep the session alive. It expects a JSON object returned from Cake.

I've created a couple Flex classes that achieve just this for a Flex Mobile App and a CakePHP backend. It should work the same for your needs.

It's in two files, the AutoValidationUrlRequest.as extends the HeaderURLRequest.as file. I'm not positive but there may be a couple variables to change, but overall it works very well and probably won't take more than a couple changes to get it working on your app.

To use it, simply create a new AutoValidationUrlRequest object and add an event listener on the headerUrlRequestComplete Event and then run AutoValidationUrlRequest.send(...) to POST. there is also a handy method called convertToPostVars for easy Cake Friendly Post variables.

AutoValidationUrlRequest.as:

package libs 
{

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.HTTPStatusEvent;

import models.LocalDeviceData;
import models.Model;

import mx.collections.ArrayCollection;
import mx.core.FlexGlobals;
import mx.utils.ObjectUtil;

[Event("LoginFailed")]
[Event("MobileUserDoesNotExist")]

public class AutoValidationURLRequest extends HeaderURLRequest
{       
    public static const LOGIN_FAILED:String = "LoginFailed";
    public static const MOBILE_USER_DOES_NOT_EXIST:String = "MobileUserDoesNotExist";
    /** 
     * will automatically be set by this class, if not set will login
     */ 
    public var requestHeaders:Object = new Object();
    private var _cookie:Object;

    /** 
     * should be an object with name of the cookie variables parsed in as key/value pairs
     */
    protected function set cookie(ck:Object):void{
        _cookie = ck;
    }

    protected function get cookie():Object{
        return _cookie;
    }

    public function AutoValidationURLRequest(){

    };

    public function send(url:String, postData:Object, generateUrlVars:Boolean = true):void{
        if(generateUrlVars){
            postData = convertToPostVars(postData);
        }
        sendRequest("http://yourwebsite.com"+url, postData, requestHeaders);
    }

    override protected function parseHeaders(e:HTTPStatusEvent):void{
        super.parseHeaders(e);
        if('Set-Cookie' in headers){
            requestHeaders['Cookie'] = parseCookie(headers['Set-Cookie']);
            //requestHeaders['User-Agent'] = headers['User-Agent'];
        }
    }


    /**
     *  returns the cookie key/val string for send requests back to the server 
     */
    protected function parseCookie(cookieString:String):String{
        var cookieObj:Object = new Object();
        var cookieBits:Array = cookieString.split("; ");
        return cookieBits[0]; 

        /*
        for each(var ck:String in cookieBits){
            var cb:Array = ck.split("=");
            cookieObj[cb[0]] = cb[1];
        }
        return cookieObj;
        */
    }

}
}

HeaderURLRequest.as:

package libs 
{

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.HTTPStatusEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;

import mx.core.FlexGlobals;
import mx.rpc.events.ResultEvent;
import mx.utils.ObjectUtil;


[Event("headerUrlRequestComplete")]

public class HeaderURLRequest extends EventDispatcher
{
    public static const HEADERURLREQUEST_COMPLETE:String = "headerUrlRequestComplete";

    public var headers:Array = [];
    public var data:Object = new Object();
    public var variables:Object = new Object();
    public var invalidFields:Object = new Object();
    public var errorMsg:String = "";


    /**
     * the headers array must contain an object with a 'name' key and a 'value' key eg: cookie: <cookieStr>
     */
    public function HeaderURLRequest():void{
    }

    public function sendRequest(url:String, postData:Object = null, requestHeaders:Object = null):void{
        var urlLoader:URLLoader = new URLLoader()
        var urlRequest : URLRequest = new URLRequest(url);

        //make it an ajax request
        urlRequest.requestHeaders.push(new URLRequestHeader('X-Requested-With', 'XMLHttpRequest'));

        for(var header:* in requestHeaders){
            var authHeader:URLRequestHeader = new URLRequestHeader(header as String, requestHeaders[header]); 
            urlRequest.requestHeaders.push(authHeader)
        }
        var urlVariables:URLVariables = new URLVariables();
        for (var vars:* in postData){
            urlVariables[vars] = postData[vars];
        }

        urlRequest.method = URLRequestMethod.POST
        urlRequest.data = urlVariables;
        urlLoader.addEventListener(Event.COMPLETE, getData);
        urlLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, parseHeaders);
        urlLoader.load(urlRequest);

    }

    public function convertToPostVars(postData:Object, prependKeyName:String = ""):Object{
        var params:Object = {};
        if(prependKeyName == ""){
            params['_method'] = 'POST';
        }
        for (var item:* in postData){
            var objtype:Object = ObjectUtil.getClassInfo(postData[item]);
            if(objtype.name == "Object"){
                var modelKeyName:String = prependKeyName+"["+item+"]";
                var subParams:Object = convertToPostVars(postData[item],modelKeyName);
                params = merge(params, subParams);
            }else{
                params["data"+prependKeyName+"["+item+"]"] = postData[item];
            }
        }
        return params;
    }

    public function flashErrorMsg():String{
        var err:String = errorMsg;
        errorMsg = "";
        return err;
    }

    protected function parseHeaders(e:HTTPStatusEvent):void{
        var i:Number=0;
        headers = [];
        for each(var header:URLRequestHeader in e.responseHeaders){
            headers[header.name] = header.value;
        i++;
        } 
    }

    protected function getData(e:Event):void{
        //trace('data: ');
        if(e.currentTarget.data == ''){
            e.currentTarget.data = '{}';
        }
        data = JSON.parse(e.currentTarget.data);

        //trace(ObjectUtil.toString(data));
        if(data.hasOwnProperty('variables')){
            variables = data.variables;
            if (variables != null){
                if(variables.hasOwnProperty('invalidFields')){
                    invalidFields = variables.invalidFields;
                    for (var error:String in invalidFields){
                        errorMsg += invalidFields[error] + "\n\n";
                    }
                }
            }else{
                //no variable data found!!
            }
        }
        dispatchEvent(new Event(HEADERURLREQUEST_COMPLETE));
    }   

    public function isEmpty(obj:Object){
        var isEmpty:Boolean = true;
        for (var n in obj) { isEmpty = false; break; }
        return isEmpty;
    }

    public function merge( obj0:Object, obj1:Object ):Object
    {
        var obj:Object = { };
        for( var p:String in obj0 )
        {
            obj[ p ] = ( obj1[ p ] != null ) ? obj1[ p ] : obj0[ p ];
            //trace( p, ' : obj0', obj0[ p ], 'obj1', obj1[ p ], '-> new value = ', obj[ p ] );
        }
        for (var p1:String in obj1){
            if(!obj.hasOwnProperty(p1)){
                obj[ p1 ] =  obj1[ p1 ] ;
            }
        }
        return obj;
    }
}
}

Also, using this with my forked version of Jose Gonzalez's CakePHP ajax_controller plugin is really handy. It basically takes any Ajax Request and converts all view variables and outputs them into a JSON object, no rendered view. Otherwise, if you're not using an ajax request, Cake will render the views normally. Good Luck!