Flex Authorize Tag

adam

It is a very rare event when I am asked to code an application which doesn’t have some security constraints. Most Java MVC frameworks provide some type of role based security for the UI out of the box. No such thing exists in Flex. I decided, after casting about for an existing solution, to write an authorize tag for myself. This component has the following properties which need to be set:

  1. roles – one or more roles (strings) which are to be evaluated against.
  2. userRoles – one or more roles(strings) which the user has
  3. components – one or more components which will be effected if evaluation of roles against userRoles fails.
  4. type – type of evaluation to be performed one of:
    • ‘hasAny’ – evaluates true if userRole exists in any of the roles
    • ‘hasAll,’ – evaluates to true only if userRoles contains all roles
    • ‘hasNone’ – evaluates to true if userRoles does not contain any of the roles.
  5. behaviour – the behviour to be applied to the specified components:
    • Disable – disables the components if evaluation fails
    • Vanish – causes the components visible property to be set to false if evaluation fails
    • Collapse – causes the components visible and includeInLayout properties to be set to false if evaluation fails

Here is the code, please feel free to copy it and use it. Any feedback would be appreciated:

package com.express.security {
import flash.events.Event;
import flash.events.EventDispatcher;
 
import mx.collections.ArrayCollection;
import mx.collections.ICollectionView;
import mx.collections.IList;
import mx.collections.ListCollectionView;
import mx.collections.XMLListCollection;
import mx.core.UIComponent;
import mx.events.CollectionEvent;
import mx.events.FlexEvent;
 
public class Authorize extends EventDispatcher{
 
   public static const HAS_ANY : String = "hasAny";
   public static const HAS_ALL : String = "hasAll";
   public static const HAS_NONE : String = "hasNone";
 
   public static const DISABLE : String = "disable";
   public static const VANISH : String = "vanish";
   public static const COLLAPSE : String = "collapse";
   private static const BEHAVIOUR_ENUM : String = DISABLE + "," + VANISH + "," + COLLAPSE;
 
   /**
    * Roles which will be evaluated against the type rules and user's roles.
    */
   private var _roles : ICollectionView;
 
   /**
    * Roles which the current user has. These will be evauated aginst the type rules and roles.
    */
   private var _userRoles : ICollectionView;
 
   /**
    * Components which will have behaviour applied to them based on the evaluation outcome.
    */
   private var _components : ICollectionView;
 
   /**
    * Specifies the type of evaluation which will be applied to the roles
    */
   [Inspectable(enumeration="hasAny,hasAll,hasNone")]
   public var type : String;
 
   /**
    * Specifies the type of evaluation which will be applied to the roles
    */
   [Inspectable(enumeration="disable,vanish,collapse")]
   public var behaviour : String;
 
   public function Authorize() {
      super();
      addEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
   }
 
   private function handleCreationComplete(event : FlexEvent) : void {
      evaluate();
   }
 
   public function evaluate() : void {
      var result : Boolean = false;
      if (_roles != null && _userRoles != null && type != null) {
         if (type == HAS_ANY) {
            result = evaluateAny();
         }
         else if (type == HAS_ALL) {
            result = evaluateAll();
         }
         else if (type == HAS_NONE) {
            result = evaluateNone();
         }
      }
      applyResult(result);
   }
 
   protected function evaluateAny() : Boolean {
      for each(var userRole : String in _userRoles) {
         if (containsRole(_roles, userRole)) {
            return true;
         }
      }
      return false;
   }
 
   protected function evaluateAll() : Boolean {
      for each(var userRole : String in _userRoles) {
         if (!containsRole(_roles, userRole)) {
            return false;
         }
      }
      return true;
   }
 
   protected function evaluateNone() : Boolean {
      for each(var userRole : String in _userRoles) {
         if (containsRole(_roles, userRole)) {
            return false;
         }
      }
      return true;
   }
 
   protected function containsRole(roles : ICollectionView, role : String) : Boolean {
      for each(var userRole : String in roles) {
         if (role == userRole) {
            return true;
         }
      }
      return false;
   }
 
   protected function applyResult(result : Boolean) : void {
      for each(var comp : UIComponent in _components) {
         switch(behaviour) {
            case DISABLE :
               comp.enabled = result;
               break;
            case VANISH :
               comp.visible = result;
               break;
            case COLLAPSE :
               comp.visible = result;
               comp.includeInLayout = result;
         }
      }
   }
 
   public function get roles():Object {
      return _roles;
   }
 
   public function set roles(val:Object):void {
      _roles = convertToCollection(val);
      evaluate();
   }
 
   public function get userRoles():Object {
      return _userRoles;
   }
 
   public function set userRoles(val:Object):void {
      _userRoles = convertToCollection(val);
      _userRoles.addEventListener(CollectionEvent.COLLECTION_CHANGE, handleCollectionChange, false, 0, true);
      evaluate();
   }
 
   public function get components():Object {
      return _components;
   }
 
   public function set components(val:Object):void {
      _components = convertToCollection(val);
      _components.addEventListener(CollectionEvent.COLLECTION_CHANGE, handleCollectionChange, false, 0, true);
      evaluate();
   }
 
   private function handleCollectionChange(event : Event) : void {
      evaluate();
   }
 
   public function convertToCollection(value : Object) : ICollectionView {
      if (value is Array) {
         return new ArrayCollection(value as Array);
      }
      else if (value is ICollectionView) {
         return ICollectionView(value);
      }
      else if (value is IList) {
         return new ListCollectionView(IList(value));
      }
      else if (value is XMLList) {
         return new XMLListCollection(value as XMLList);
      }
      else {
         // convert it to an array containing this one item
         var tmp:Array = [value];
         return new ArrayCollection(tmp);
      }
   }
}
}

5 Responses to “Flex Authorize Tag”

  • Nitin Gupta Says:

    Can you please give some example to use the Flex Authorize Tag code.

  • Nitin Gupta Says:

    When I am trying to use the above like

    it is giving error Component declarations are not allowed here. (Note: visual children must implement mx.core.IUIComponent

  • adam Says:

    Hi Nitin,

    I will post an example later this weekend if I get a chance but I think your problem might be where you have placed the authorize tag in your mxml. Place it at the top level, at the same place where it is valid to supply style tags, etc. Remember it is not a visual component.

  • Nitin Gupta Says:

    in this code when i am trying to pass all the compopnet as array in component property i am geting null in each object of array in authorise class. Will you please help me in this.

  • adam Says:

    Can you post your mxml snippet here in your comment? I will go through it and let you know what the problem is.

Leave a Reply