User specific login information is usually stored in session variables in any web application. However, Flex doesnt have anything called session variables in it. So how do we save this information across the whole application. Static classes come to the rescue here. This can also be achieved by use of shared objects and Singletons but I am going to focus on static classes for now.
A static class holds the information in it once declared and is very useful for such scenarios. Typically, after you are done with the username/password authentication in your Flex app, you would need to store the data in a static class to be able to access it from anywhere in your application.
Here is how we do it:-
[as3]
package classes.UserInfo
{
public class UserInfo
{
private static var myUserName:String = "";
private static var myFullName:String = "";
public static function get UserFullName():String
{
return UserInfo.myFullName;
}
public static function set UserFullName(param:String):void
{
UserInfo.myFullName = param;
}
public static function get UserName():String
{
return UserInfo.myUsername;
}
public static function set UserName(param:String):void
{
UserInfo.myUserName = param;
}
public static function getInstanceMemento():Object
{
var o:Object = {
myUserName: UserInfo.myUserName,
myFullName: UserInfo.myFullName
};
return o;
}
public static function setInstanceMemento(param:Object):void
{
UserInfo.myUserName = param.myUserName;
UserInfo.myFullName = param.myFullName;
}
}
}[/as3]
Once you have the class ready, you can use it to set the values. First , import the class you wrote in your mxml file.
[as3]import classes.UserInfo;[/as3]
Then, after you are done with your authentication process, you can set the values :-
[as3]UserInfo.myUserName = "joebloggs";
UserInfo.myFullName = "Joe Bloggs";[/as3]
and you can read this information anywhere in your application this way :-
[as3]UserInfo.myFullName[/as3]
or you can use the getInstanceMemento() or setInstanceMemento() to do the above in one go!
Obviously, you can expand this class to include a lot of other informaion related to the user e.g. email, phone, fax etc and use it wherever required.
I’m a newbie to Flex – but why would you set the values directly instead of using the set function?
Ray, you are right. You can use both getters and setters and also the getInstancememento and setInstancememento functions to set or get data. I choose to demonstrate the setting of variable directly though. Its upto the developer really.
Ray, you could use getInstanceMemento to get Object instance instead of class instance if you need to send it to Java RPC (and you don’t map classes with RemoteClass). In this case in Java you’ll get Hashmap. You can do the same with CF RPC and CF web service.
You would also use setInstanceMemento while sending data in opposite direction. So you’re sending Hashmap from Java and you need fill your class. Instead of asigning properties one by one you could use setInstanceMemento().
Makes sense guys – thanks for the comments.
Comment 1:
In Flex, using an MVC framework, you could point your user class (AKA, a model or a value object) through the model. If you import the UserInfoClass (really a value object/model), you’ll start to have classes that point to model data with 100s of references.
As such, you could do this:
Import and bind the model in all of your command classes.
In your Model, you’d need to bind and define a reference to your UserInfoModel
Then, you’re model is centralized and points to subclasses, but the ‘model’ as a whole is accessible from anywhere.
Ex:
LoginCommand:
model.UserInfoModel.userName = loginEventResponse..userName
UpdateUserCommand:
model.UserInfoModel.userName = updateUserResponse..userName
Comment 2:
var o:Object =
The problem with using a simple object name is that it makes Find & Replace a nightmare, should you need to add more flexibility later.
Best to use var obj:Object = new Object();
You’ll find as your project scales that you’ll be adding obj1 and obj2 quite regularly.
I would also add for newbies reading this blog posting that the session information can still be stored in a coldfusion session scope. There’s no need for anyone to return the password, for the sake of discussion, back to the client.
David: sending password back shouldn’t be a problem as the password has to be sent from client to server 🙂
about Object: that is a big problem of AS3, basically it shouldn’t let you use Object in the way as it is right now. If you have to use it then use it only when you have to send data out of the client.
David, what you mentioned can be done in CairnGorm which I personally find a bit messy to work with. But if I were using CairnGorm, I would have done the way you suggested. I am happy with simple plain Flex without any frameworks though 🙂
Flex is a framework itself 😉
@Radek
I’m probably too brief in posts. Sending passwords back and forth from the client presents a security risk. Namely, you would need to be concerned with user-sensitive information being viewed over the wire, and you would need to be concerned with session hijacking. The endorsed approached for password changing, for example, is to never pass the password back to the client from the server, but rather, to have the user send his old password and new password to the server from the client, where the old password is validated against the current password. If you pass the password back to the client each login, you’re exposing the user’s security risk for each login-request, which is probably going to be 100x greater than the initial “Create Account” request.
regarding objects:
When I pass parameters to CF from Flex, I always bundle them up. Also, in my command’s request, I might do some formatting or cleaning, but I always pass a single object for brevity. If you’re really lazy, it’s pretty kosher to pass a model as an object, in my opinion. You could pass a value object, too, for the sake of pure MVC fans, but a model and its instances will cast as an object:
@Anuj
Cairngorm is a bit tricky to work with, but it’s useful on larger projects. For me, with a project that has 10+ commands, there’s a wonderful simplicity knowing that by binding sub-classed models to my main Model, all I have to do is type:
model.[and all of the model attributes and subclassed models along with their attributes] are two selections through a list away.
Conceptually, the benefits are *tremendous*.
You, and everyone else, should always know the Mapped path to the data-stores, even if they are sub-classed.
If you don’t like it, Model-Glue for Flex is more forgiving and is similar to the Model-Glue for CF approach :
http://www.model-glue.com/blog/index.cfm?mode=entry&entry=0FBD76D2-3048-55C9-43D34471520B4215
the benefits are definitely there David and one day I will try Cairngorm or Model-Glue 🙂 I am sure it must be worth the effort. However, this post of mine was to demonstrate the use of static classes and how they can be used…..I understand your concerns about username/password security but ideally, static classes can be used for any reason if not storing user data.
Gotcha 🙂
Best,
DB
hi how do i apply the above class to my login form? i am using a coldfusion backend to query my db that stores login info like password, username and fullname and i am using remote objects. if you dont mind please show an example of applying it. thanks
@John, you would use the RemoteObjects to authenticate your user and if successful, you can then use this class to save the user info in Flex. I hope that gives you some idea.
hi thanks for the quick reply. how would i do this? if you dont mind please guide me on how i would save user info from db and display it in some text inputs. am pretty new to flex. ope am not being a bother.
for newbies this example is very plain. i cant understand how to apply this to my flex login form plus my username and password are not hard coded, they are stored in database. please clarify
@John, @zionist, I will try and come up with a better explanation. Need a couple days time though. Cheers.
hey i appreciate it. hope am not taking alot of your time.
hi Anuj, any luck yet on that solution?
Not yet John, I will try and come up with something this weekend. Sorry, its going very busy here.
oh thanks for the quick reply. am very great full that you are actually helping. thanks a lot man. looking forward
hi, nice code example. i still have a problem on how to get data which has not been inputed in the login form into the class for example the login form has 2 fields (username and password), how do i get fullname and email from my remote object call into the class.please check your gmail. i have attached the code of my login system and a cfc that gets the data from the db. thanks
hi sorry for being such a burden. on a login form there are two text input fields(username and email) which a validate with a database to see if they both match and then login is successful. how does one get the email and other info to show up in the profile page if there are no inputs for them on the login page. i hope my question is clear. attached is the UserInfo class am using as yo suggested and also my login form. in my database i have username, password, email etc stored and the user is authenticated against it by supplying a correct combination of username and password. when login is successful i would like the user to view his credentials like username, password, email etc so that he/she can be able to change them. i have attached my code to your email thanks so much
Hi Anuj, any solution
John, when you run your authenticate function from the database, your query can get other fields like email, age etc as well and if the login is successful, you can set the UserInfo.email and UserInfo.age fields etc at that point. Let me know if that doesnt make sense still?
Hi Anuj, you are right that when i run my authenticate function from the database, my query can get other fields like email, age etc as well. But what I don’t understand is that On login success I have something like this “UserInfo.UserName = pop.username_txt.text;” what shall UserInfo.Email equal to?
Hi John, that would be UserInfo.email = yourRemoteObject.emailId , and you must add the email Property to the UserInfo class as well like it already has for Username and Password.
hi i have tried do that (UserInfo.Email = pop.authManager.email;) and in the email text input on the profile page this is what is returned “[object Operation]”. i did include email Property to the UserInfo class. authManager is my remote object and email is the column in the database.
you need to make sure that the email returned from the remote object is actually a string.
Also, try doing pop.authmanager.EMAIL (ColdFusion converts to uppercase) .
If nothing else works, try dumping the pop.Authmanager and see what it is actually returning.
mx.controls.Alert.show(mx.utils.ObjectUtil.toString(pop.authManager));
That should give you some heads up I think.
the email returned from the remote object is a string. this is what is returned by the dump
(mx.rpc.remoting.mxml::RemoteObject)#0
channelSet = (mx.messaging::ChannelSet)#1
channelIds = (Array)#2
[0] “my-cfamf”
clustered = false
configured = true
connected = true
currentChannel = (mx.messaging.channels::AMFChannel)#3
channelSets = (Array)#4
[0] (mx.messaging::ChannelSet)#1
connected = true
connectTimeout = -1
endpoint = “http://localhost:8500/flex2gateway/”
failoverURIs = (Array)#5
id = “my-cfamf”
netConnection = (flash.net::NetConnection)#6
client = (mx.messaging.channels::AMFChannel)#3
connected = false
objectEncoding = 3
proxyType = “none”
uri = “http://localhost:8500/flex2gateway/”
polling = false
pollingEnabled = false
pollingInterval = 3000
protocol = “http”
reconnecting = false
requestTimeout = -1
uri = “http://{server.name}:{server.port}/flex2gateway/”
messageAgents = (Array)#7
[0] (mx.rpc::AsyncRequest)#8
channelSet = (mx.messaging::ChannelSet)#1
clientId = “562FC6E4-9009-00E6-7DB1-45BC26E38A84”
connected = true
defaultHeaders = (null)
destination = “ColdFusion”
id = “B686B877-6C13-DB78-A8A5-AD562E9B1FE7”
requestTimeout = -1
session = (null)
subtopic = “”
concurrency = “multiple”
destination = “ColdFusion”
EMAIL = (mx.rpc.remoting.mxml::Operation)#9
argumentNames = (Array)#10
arguments = (Object)#11
concurrency = “multiple”
lastResult = (null)
makeObjectsBindable = true
name = “EMAIL”
service = (mx.rpc.remoting.mxml::RemoteObject)#0
showBusyCursor = true
endpoint = (null)
loginUser = (mx.rpc.remoting.mxml::Operation)#12
argumentNames = (Array)#13
arguments = (Object)#14
concurrency = “multiple”
lastResult = true
makeObjectsBindable = true
name = “loginUser”
service = (mx.rpc.remoting.mxml::RemoteObject)#0
showBusyCursor = true
makeObjectsBindable = true
operations = (Object)#15
EMAIL = (mx.rpc.remoting.mxml::Operation)#9
loginUser = (mx.rpc.remoting.mxml::Operation)#12
requestTimeout = -1
showBusyCursor = true
source = “login_example.cfc.login”
did you try pop.authauthManager.EMAIL ?
yes i tried pop.authManager.EMAIL and it also returns “[object Operation]”.
hi what could be the problem?
hi, i have just sent the code
hi am still a newbie in flex and actionscript. please just guide me. thanks
hi Anuj i am not that good with actionscript let alone dispatching events, i just know the basics. i still have a long way to but please help me out on this one. thanks for the help though. you have been kind.
help please… help
@Hi john, we are going to have to take this up on IM I guess. email me your MSN info and we will take it from there.
hi, are you online yet?
[…] reader asked me a question based on my earlier post about how to maintain Login information in Flex and how to pass data along with Custom […]
hello,
Could you tell me what will happen if a user logs in by using his credentials and then he refreshes the browser.??
will he be thrown to the login page or the home page..
well i believe that the static class will not contian any data when the flex application loads after the browser is refreshed.
if a user refreshes the browser, they will be presented with a login screen as the session is not stored anywhere….