12 Replies Latest reply on Apr 14, 2009 7:47 PM by fuyuko1979

    Cairngorm login authentication problem

    fuyuko1979

      Hi there,

       

      Currently I am trying to make an application which allows a user to login and depending on their permission level they may have complete access to the application or have limited access.

      Currently I have set it up so that when the user submits their login details, I dispatch an event which calls the login command and the login delegate validates the result, if successful then it updates a variable called loginAccess in the model.

      In the main mxml, I set it up so that when it first loads the currentState property is bound to the loginAccess in the model,  so when one logs in and is successful then the variable loginAccess is updated which then updates the currentState of the main app. This is working totally fine as a simple login logout function, however I need to present the viewer with something different depending on their permission level - one which allows the whole application to be accessed if you are an admin and one that is for a guest user who can only view some parts of the application.

       

      So what I think would be the most easiest is if the user is a guest then I can hide or remove certain components and controls like tabs, buttons and labels that are prohibited and if the user is an admin then do nothing.

       

      This is where my problem lies, I have no way of determining if a user is a guest or an admin at the point when the user first logs in.

      In another words, if I make an if/else statement such as: if user is guest then remove the 2nd child from the tab navigator,  then I have no where in my main application to call this because if I call it at creationComplete it's too early, the user has not logged in...

       

      Am I making sense here?

       

      I'm wondering if I can dispatch some kind of an event from the LoginCommand once the user permission is determined which will then trigger a function in the main mxml that will perform a function to remove components (if they are a guest), however I am not sure how to do this as when the user first logs in, the login event is dispatched from the login component and not from the main mxml.

       

      I'm not even sure if my approach is the most practical way or whether there is a better way.

      Please if anybody has suggestions that would be great,

      I created this application a few weeks ago totally in flex and now am converting it to cairngorm as an exercise and everything is done except for this part.

       

      thanks in advance for any help!

       

      Fuyuko

        • 1. Re: Cairngorm login authentication problem
          ergo_eleven Level 1

          Hi Fuyuko!

           

          You are experienced one of the biggest problem of Cairngorm - Control cannot notify View.

          I usualy solve this as follow:

          1) strore pointer of needed view class in model (for example model.postsGridView   :   PostsGridView)

          2) create command that know how playing with theese view class (i.e. how to hide some columns in model.postsGridView)

          3) create neccessary event and register command in controller with its event (i.e. addCommand(SecurityEvent.UPDATE_POST_GRID_VIEW, UpdatePostGridViewCommand);    )

          4) in command call public methods.

           

          I do not say this is the best practice solution, but it works for me.

           

          In Mate this figures out in very elegant way: you register mate event, it invokes any method in any class instance (it works even if it doesn't exists at this moment). See on http://mate.asfusion.com/page/documentation/tags/methodinvoker

          • 2. Re: Cairngorm login authentication problem
            fuyuko1979 Level 1

            hi ergo_eleven,

             

            Thanks so much for your reply!

            I'm still a bit confused as the whole cairngorm and oop is still a new thing for me not to mention flex.

            I have done point 1 which is to reference my views in the model locator.

            But I'm not sure how to do number 2.

            You say create a command, do you mean a class? Even so, I'm not sure how to write one which will get rid of certain controls in the component.

             

            Just before, I tried modifying my loginCommand so that when it retrieves the permission level from the loginDelegate, it verifies whether it is a guest or admin and if it is a guest I tried to remove a button from model.openTasks.editBtn - where openTasks is my component and editBtn is the button that I want to get rid of....but as soon as I do this it gives me an error saying it can not reference a property or a method with a null object reference... but the thing is, everything is instantiated on creationComplete and therefore I don't think i am referencing something that is not there....

             

            if you can elaborate on your points that would be great!

            thank you,

             

            Fuyuko

            • 3. Re: Cairngorm login authentication problem

              Hi fiyuko,

               

              I just happened to see your post as I am myself about to get into Cairngorn.

               

              I can't say specifically in Flex terms how to implement your access control design. But I have implemented such control schemes many times in my client/server applications, and would like to suggest you implement access control/security in a superclass of all major components.  Then subclass your nav bars, tabs, views, etc. from the superclass and implement the inherited security method for all your components. This way you won't repeat yourself many times throughout the app writing access control methods for each piece part - in other words - DRY.

               

              So for instance, your superclass will have a method - CheckSecurity, and in all your instances you can overide this method and do the appropriate action depending on the user's status/permissions level - eg. disable all the controls in the view if the user is a Guest(ie. make the form read only). Likewise for navigation controls(menus, nav bars, tabs, etc), in the CheckSecurity method you would disable/enable a control element or set it's visible property=true/false depending on user status.

               

              This approach may be too much this late in your project life cycle, but generally speaking, security should be designed early in the game.

               

              regards,

               

              -fred

              • 4. Re: Cairngorm login authentication problem
                ergo_eleven Level 1

                Hi Fuyuko!

                 

                Sorry for delaying with answer - i was toooo busy to do that.
                You wrote:
                >> You say create a command, do you mean a class?

                 

                Yes, the Cairngorm command is a Class. It must looks like:

                 

                    public class MyCommand implements ICommand, IResponder
                    {
                        private var model : ModelLocator = ModelLocator.getInstance();
                        public function execute (event : CairngormEvent) : void
                        {
                            // Call service here
                        }
                        public function result (data : Object) : void
                        {
                            // Apply security here
                            model.openTasks.editBtn.visble = false;
                        }
                        public function fault (event : Object) : void
                        {
                            // Something went wrong
                        }
                    }

                 

                >> it gives me an error saying it can not reference
                >> a property or a method with a null object reference...
                   
                I guess you trying to access to private property. I.e. you create that button in private scope.
                In you component you should declare that button like

                 

                    public var editBtn : Button;

                 

                Or define it in mxml, and compiler do this for you:
                   
                    <mx:Button id="editBtn" />
                   
                >> but the thing is, everything is instantiated on creationComplete

                 

                It is a bad idea. Flex has some specific component's model. Its implies deffered component creation and validation mechanism.
                All children must creating in special function createChildren(). You must use something like this:

                 

                    override protected function createChildren () : void
                    {
                        super.createChildren();

                 

                        if (!editBtn)
                        {
                            editBtn = new Button();
                            editBtn.label = "hello";
                            editBtn.addEventListener("click", onEditButtonClick);
                            addChild(editBtn);
                        }
                        ...
                    }

                 

                For more info see "–°reating advanced components" at http://livedocs.adobe.com/flex/3/html/help.html?content=ascomponents_advanced_2.html

                 

                But for begining i suggest you creating componet in MXML.

                 

                Hope this helps!

                1 person found this helpful
                • 5. Re: Cairngorm login authentication problem
                  run,ryan! Level 3

                  You can access or modify view in your command without any problem.

                  You can create a variable in your modelLocator which refer to the compoment you want to modify on your view, (assign the ref when component complete creation), or ref to the component by Application.application.root.xxxxxxx

                  then you can do whatever you want in your loginSuccess function, or command

                  1 person found this helpful
                  • 6. Re: Cairngorm login authentication problem
                    fuyuko1979 Level 1

                    hi run ryan and ergo_eleven,

                     

                    Thanks for your reply but no luck so far.....

                     

                    ok so let me just step by step explain what i have done:

                     

                     

                    1. I have a component called OpenTasks which is created in mxml, and in this component I have a button defined as:

                    <mx:LinkButton x="569" y="342" label="Edit" id="editBtn" click = "edit(event)" toolTip="Edit this task"/>

                    This component is instantiated in my main mxml file.

                     

                    2. In my modelLocator I have created a public var to reference to this OpenTasks component:

                    public var openTasksComp:OpenTasks;

                     

                    3. In my loginCommand,I instantiate the modelLocator and then do the necessary login stuff like instantiate loginDelegate, send user name and password then retrieve the response which I send back to the loginCommand.

                    At this point I make an if else condition like this in my result function:

                     

                    if(data=="guest")

                    {

                         model.openTasksComp.editBtn.visible = false;

                         Alert.show("this is a guest");

                    }

                     

                    This seems right to me, the Alert works and the editBtn appears in the drop down menu, meaning it knows that the editBtn is a child of openTasksComp.

                     

                    However when I run the application, I get the error:

                    TypeError: Error #1009: Cannot access a property or method of a null object reference.
                        at com.taskmanager.cairngorm.commands::LoginCommand/result()[C:\Users\Fuyuko\Flex\Hemisphere TaskManager\src\com\taskmanager\cairngorm\commands\LoginCommand.as:33]

                     

                    I don't know why!!

                    Because openTasks is instantiated in the main mxml so as soon as the main mxml loads, the openTasks component exists with the edit button - however you cant see it because on first load, the currentState is set to "login", but as soon as login is successful, the state is set back to " " and one sees the edit button - I even traced the button out when the application first loads and it was able to refer to it which means it's there from the beginning!, but as soon as I log in and try to either remove or change the visibility of the edit button, it gives me that error. Whats even worse is that I tried tracing it out after logging in, and it is able to refer to it but still gives that same error.....

                    I also tried using Application.application.openTasks.editBtn and still gives the same exact error....

                    HOWEVER I was able to remove the canvas which holds the editBtn using the application method:

                     

                    Application.application.openTasks.removeChild(Application.application.openTasks.messageVie wer);

                     

                    This worked and gave me no errors but as soon as I reference the button, it does not seem to like it.... I really don't know why!

                     

                    I also tried this:

                    Application.application.openTasks.removeChild(Application.application.openTasks.editBtn);

                     

                    which gives me the error message:

                     

                    ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.

                     

                    this is driving me insane.....

                    • 7. Re: Cairngorm login authentication problem
                      fuyuko1979 Level 1

                      ok, I think I got it working....

                       

                      I tried doing this:

                       

                      Application.application.openTasks.messageViewer.removeChild(Application.application.openTa sks.editBtn);

                       

                      and this has successfully got rid of the edit button,

                      why I had to reference it like that is beyond me since editBtn is the child of the messageViewer but also the child of openTasks....anyway now it works...

                       

                      However It still doesn't work at all if I try to refer to it through the model as in:

                       

                      model.openTasksComp.messageViewer.removeChild(model.openTasksComp.editBtn);

                       

                      it still gives this error:

                      TypeError: Error #1009: Cannot access a property or method of a null object reference.

                       

                       

                      i wonder why....?

                      • 8. Re: Cairngorm login authentication problem
                        ergo_eleven Level 1

                        You should use (assuming the button id is editButton):

                        var editButton : Button = model.openTasksComp.messageViewer.getChildByName("editButton");
                        model.openTasksComp.messageViewer.removeChild(editButton);
                        

                        or

                        var editButton : Button = model.openTasksComp.messageViewer.getChildByName("editButton");
                        
                        Application.application.openTasks.messageViewer.removeChild(editButton);
                        

                        But the last is bad code practice.

                        And I think it's better to hide control rather removing it:

                        var editButton : Button = model.openTasksComp.messageViewer.getChildByName("editButton");
                        editButton.visible = false;
                        editButton.includeInLayout = false;
                        
                        • 9. Re: Cairngorm login authentication problem
                          run,ryan! Level 3

                          how did u init model.openTasksComp?

                          it should be inited when you create your openTasksComp on view

                          • 10. Re: Cairngorm login authentication problem
                            fuyuko1979 Level 1

                            hi guys, thanks for your help...

                             

                            Ergo_eleven, I tried doing it your way but still gives me the same error message:

                            TypeError: Error #1009: Cannot access a property or method of a null object reference.

                             

                            I tried every possible way of referencing that button using the model the way you showed me but every time it gives me that error....

                             

                            I would also prefer not to use Application.application but so far it seems like this is the only way I can refer to the controls....

                             

                            I have made all of them invisible as you suggested instead of removing them except this doesn't work with a tab navigator, the visibility does not seem to change so instead I have to remove it....

                             

                            run, ryan!

                            the openTasks component is initialised in the main application like this:

                             

                            <mx:TabNavigator width="732" height="536" y="70" id="taskNavigator" creationPolicy="all">
                                        <view:OpenTasks label="Open Tasks" width="100%" height="100%" id="openTasks" toolTip="View Open Tasks" />
                                        <view:ClosedTasks label="Closed Tasks" width="100%" height="100%" id="closedTasks" toolTip="View Closed Tasks"  />
                                        <view:NewTasks label = "Add/Edit Task" width="100%" height="100%" id="newTasks" toolTip="Add or Edit Tasks" />

                            </mx:TabNavigator>

                             

                            Is that what you mean?

                            I also refer to it in my modelLocator by doing this:

                             

                            public var openTasksComp:OpenTasks;

                             

                            and in my command where I try to hide the controls, I instantiate the model by typing:

                             

                            private var model : ModelLocator = ModelLocator.getInstance();

                             

                            I guess the problem is that when I use the model, the application seems to not be able to find the button....the button by the way is a link button....

                             

                            hmm.... how frustrating!!!

                            • 11. Re: Cairngorm login authentication problem
                              run,ryan! Level 3
                              public var openTasksComp:OpenTasks;

                              its only declaring a variable, not initialized.

                              you should make it refer to your comp by

                               

                              <view:OpenTasks label="Open Tasks" width="100%" height="100%" id="openTasks" toolTip="View Open Tasks" creationComplete="initComp()"/>
                              <script>
                              private function initComp():void
                              {
                                   var model:ModelLocator = ModelLocator.getInstance();
                                   model.openTasksComp = openTasks;
                              }
                              • 12. Re: Cairngorm login authentication problem
                                fuyuko1979 Level 1

                                Thank youuuuuuuuuuuuuuuuuuuuuu!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                                You have saved my day!!!!!!!!!

                                thank you thank you thank you!!!!

                                that worked!! and it now makes total sense, I thought I was already referencing the component in the model but now it makes absolute total sense, so thank you sooo much!!!

                                 

                                I have to ask you one last small question...

                                I have a tab navigator in the main mxml - actually I pasted the code in my previous post - and I would like to get rid of the "newTasks" tab all together at the same time when I am getting rid of the edit button and others.

                                Changing the visibility of this tab does not work so I removed it by going:

                                 

                                Application.application.taskNavigator.removeChild(model.newTasksComp);

                                 

                                but I wonder what I can put in replacement of Application.application in order to reference the main mxml....?

                                 

                                thanks again so much for your help!!!