Skip to main content

Orchestrating Login and Roles-Based Security in Ext JS and Sencha Touch

The issue of logins and roles-based security often comes up in my Ext JS and Sencha Touch classes. The sad reality is that anyone who knows how to open the browser’s JavaScript debugger is able to “hack” your application. Therefore, security is something that *must& be handled at the application-server level as there is no current method to adequately secure your JavaScript code.
Having said that, most corporate apps still require logins and roles-based security as functional requirements. A user must enter credentials and their button/menu selections need to be tailored to a specified role.

Typically, your app.js file simply invokes a login dialog as illustrated by the following code snippet:
1
2
3
4
5
6
7
8
9
10
// code listing 1: app.js
Ext.application({
    controllers: ["Main"],
    views: ["Main"],
    name: 'LoginAppDemo',
    autoCreateViewport: false,
    launch: function() {
        Ext.create("LoginAppDemo.view.LoginForm")
    }
});
Let’s also assume that we’re going to put together a simple login form inside of a floating window. Why a floating window, you ask? Because login forms are always cooler if they float and are draggable, of course!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// code listing 2: LoginForm.js
Ext.define("LoginAppDemo.view.LoginForm", {
 extend: 'Ext.window.Window',
 alias: 'widget.loginform',
 requires: ['Ext.form.Panel'],
 title: 'Please Log In',
 autoShow: true,
 height: 150,
 width: 300,
 closable: false,
 resizable: false,
 layout: 'fit',
 items: [
  {
   xtype: 'form',
   bodyPadding: 5,
   defaults: {
    xtype: 'textfield',
    anchor: '100%'
   },
   items: [
    {
     fieldLabel: 'User Name:',
     name: 'username',
     allowBlank: false
    },
    {
     fieldLabel: 'Password:',
     name: 'password',
     allowBlank: false
    },
   ],
   buttons: [
    {
     text: 'Log in',
     formBind: true,
     disabled: true,
     handler: function(b,e) {
      var formDialog = b.up('loginform');
      var form = b.up('form');
       
      // fire custom event for the controller to handle
      formDialog.fireEvent('login',formDialog,form,form.getValues());
     } // handler
    } // login button
   ] // buttons
  } // form
 ] // items
})
Note that in the preceding example, when the user clicks the ‘Log in’ button, I fire a custom ‘login’ event and pass references to the login window, the login credentials form, and the data that the user entered into the form up to the controller (listed below).
From within the login handler, I make an Ajax call to the server in order to retrieve information about the user profile. In a production environment you would make this call via HTTPS to your application server (.php,.aspx,.jsp,.cfc, etc.).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// code listing 3
Ext.define('LoginAppDemo.controller.Main', {
 extend: 'Ext.app.Controller',
 requires: ['LoginAppDemo.user.Profile'],
 views: ['LoginForm','Viewport'],
     
 init: function(application) {
  this.control({
   "loginform": {
     login: this.onLogin
    }
  });
 },
 onLogin: function(loginDialog,loginForm,loginCredentials) {
    
   var me = this;
   // authenticate
   Ext.Ajax.request({
    url: 'resources/sampledata/cred.json',
    params: {
     username: loginCredentials.username,
     password: loginCredentials.password
    },
    success: function(response) {
      
     // convert text response to javascript object
     var data = Ext.decode(response.responseText);
     
     // if server response contains "firstName" node, then success!        
     if (data.firstName) {
      // instantiate user info in global scope for easy referencing
      LoginAppDemo.User = Ext.create("LoginAppDemo.user.Profile", {
                        firstName: data.firstName,
                        lastName: data.lastName,
                        roles: data.roles
      });
      
      // destroy login dialog
      loginDialog.destroy();
      Ext.Msg.alert("Login Successful",
                Ext.String.format("Welcome {0} {1}",
                          LoginAppDemo.User.getFirstName(),
                          LoginAppDemo.User.getLastName())
      );
      // load main UI
      Ext.create("LoginAppDemo.view.Viewport");
  } else { // login failed
    Ext.Msg.alert("Invalid credentials",
                  "You entered invalid credentials.",
                  function() {
               loginForm.getForm().reset();
                  }
    );
  }
 }
});
}
});
Your app server would subsequently run a custom sql query to ensure that the passed username and password were valid and return a response similar to the following:
1
2
3
4
5
6
// code listing 4: cred.json
{
 firstName: 'Steve',
 lastName: 'Drucker',
 roles: 'admin'
}
Your app server would also set up session management for the user, typically consisting of some sort of session-based cookie hack since not every browser supports the establishment of persistent (html5 websocket) connections. Each subsequent data request to the server would use this cookie to determine whether the user had the appropriate rights to download the data that was requested.
From a UI perspective, however, we are simply concerned with caching the user’s identity and roles information in a location that could be easily accessed by our view and controller logic. Lines 33-37 of code listing 3 above instantiate the custom component described in code listing 5 at the root of your application’s namespace for easy global access.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// code listing 5
Ext.define("LoginAppDemo.user.Profile", {
     
  config: {
    firstName: '',
    lastName: '',
    roles: []
  },
  isUserInRole: function(roles) {
   for (var i=0; i
    if (Ext.Array.contains(this.getRoles(),roles[i])) {
     return true
    }
   }
   return false;
  },
  constructor: function(config) {
    this.initConfig(config);
    this.callParent(arguments);
  }
});
As illustrated by the following toolbar class, once the framework described above is in place, you can simply test the features of your app before outputting them to the user.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Ext.define("LoginAppDemo.view.MainToolbar", {
 extend: 'Ext.toolbar.Toolbar',
 alias: 'widget.maintoolbar',
 requires: ['Ext.toolbar.TextItem'],
     
 initComponent: function() {
  var items = [
   {
    xtype: 'tbtext',
    text: 'Login and Roles-Based Security Simulator'
   },
   {
    xtype: 'tbfill'
   }
  ];
  if (LoginAppDemo.User.isUserInRole(["admin"])) {
   items.push({ xtype: 'button', text: 'For Admins'});
  }
  if (LoginAppDemo.User.isUserInRole(["admin","users"])) {
   items.push({xtype: 'button', text: 'For Admins or Users' });
  }
  if (LoginAppDemo.User.isUserInRole(["nobody"])) {
   items.push({xtype: 'button', text: 'For nobody' });
  }
  Ext.apply(this, {items: items});
  this.callParent(arguments);
 }
});

Comments

  1. Wonderfully written article!! The info you are sharing here is most beneficial for me.Thanks for sharing!!!!

    Hire JavaScript developer

    ReplyDelete
  2. stigcaZtio-i Dave Hundley program
    Click
    growlaytouchsders

    ReplyDelete
  3. This is a well informative and interesting post on this topic "Orchestrating Login and Roles-Based Security in Ext JS and Sencha Touch". Are you looking to hire a Javascript Developer in India? If so, you’ve come to the right place. With the rise of web development, Javascript has become one of the most popular programming languages used for building websites and applications. As such, it is important that you have a qualified and experienced Javascript developer on your team.

    ReplyDelete

Post a Comment

Popular posts from this blog

ExtJS 4 with Spring MVC Example

Introduction When developing a brand new application for the company I work for, one of the first thing I implement is "authentication". Not only is this process generally a prerequisite to access many other functions but it is also very simple and covers every layer of an application, from GUI to the database. So instead of another minimalistic "Hello World" tutorial, here is a "Login/Password" example, using 2 famous technologies : Spring MVC and ExtJS 4.   Prerequisites Because this tutorial is quite long, I won't go into the details of each technology I used but I will mainly focus on how ExtJS and Spring can be nicely used together. So here are the things you should know before continuing : Spring framework (good knowledge) Spring MVC (basic knowledge. See  Spring MVC Official Documentation  for details) ExtJS "application architecture" (see  Sencha Docs  for details) Eclipse IDE + Tomcat 6 (or any other web container) You a...

ExtJS - Grid panel features

What can we do with ExtJS GridPanel? I have to develop a lot of applications in my web app and I see that grid component of ExtJS may fit in. However, I am not aware of what all things I can do with the - off the shelf available framework pieces - available plug-ins in the marketplace and - custom development through my own developers This is a typical question that we hear from the business users who wants to design an application by keeping the framework’s capability in perspective. In this article I have tried to put the list of stuff you can do with grid and hopefully that shall enable you to take advantage of the beauty of ExtJS. Pre-requisites This article assumes that you are familiar with basics of ExtJS What are the available options? In this section I will be taking you through some of the commonly seen usage of ExtJS grid panel. While covering all the capabilities of grid may not be possible, I am sure it will be helpful for the business users who want to...

EXT JS 4: EMPTY VALUE IN A COMBOBOX

EXT JS 4: EMPTY VALUE IN A COMBOBOX Often, in an Ext JS combobox, it is difficult to go back to an empty value once you have selected an item, particularly if “forceSelection” is set to true.  Here is my roundup of alternative solutions found from around the web… 1. Override beforeBlur The solution from   http://www.sencha.com/forum/showthread.php?182119-How-To-Re-Empty-ComboBox-when-forceSelection-is-Set-To-TRUE  overrides beforeBlur on the combbox to clear out lastSelection.  Here is a copy of the override from the thread: 1 2 3 4 5 6 7 8 9 10 11 12 13 Ext.create( 'Ext.form.field.ComboBox' , {      ...      allowBlank: true ,      forceSelection: true ,      beforeBlur: function (){          var value = this .getRawValue();          if (value ...