Customizing Spring Security Login using ExtJS in Grails Apps

I’ve been wanting to learn Grails for sometime and finally had the time to try out this web application framework. Grails is a very impressive framework, it is really about productivity and simplicity. Some of the benefits are scaffolding, testing framework, easy to create plugin and seamless integration with Spring and Hibernate. As part of my first attempt, I am customizing the Spring Security Login using ExtJS in a simple Grails application. The focus here is on the integration with Spring Security and ExtJS rather than Grails. I am using SpringSource Tool Suite (STS 2.7.1) to develop the demo application. The application is to display Quotes randomly and ability to maintain them. Let’s begin the integration and customization steps.

Step 1: Install the Spring Security Plugin

Spring Security is not built-in Grails, to begin the integration execute the following Grails command.

install-plugin spring-security-core

Step 2: Generate Domain Classes

 This step will create basic domain classes needed to store user information and the controller that handle the authentication. After executing the command below you will see several files being added to your project, such as LoginController, auth.gsp, denied.gsp, User, Role, UserRole, RequestMap. The domain class name for user and role is up to you to define and if you have an existing user domain, you must decide to integrate it (possibly by extending your domain class to the generated user class). Just a note that the RequestMap is an option and will look into it at later step.

s2-quickstart org.xaab.qotd User Role RequestMap

Step 3: Define URL mapping for login and logout

In order the make the login and logout controller reachable, the URL mappings must be added into UrlMapping.groovy

class UrlMappings {
	static mappings = {
		"/login/$action?"(controller: "login")
		"/logout/$action?"(controller: "logout")

Step 4: Add Access Control to the Controller

The need for this step depends on how you wants to control the access. You can use @Secured annotation to limit access to certain part of the application. In this example, I am not using annotation to limit the access, instead I define dynamics request maps which is shown in the Step 5. The following code is just an example of how @Secured can be used in the controller.

package org.example
import grails.plugins.springsecurity.Secured

class PostController {
    def followAjax = { ... }

    def addPostAjax = { ... }

    def global = { ... }

    def timeline = { ... }

    def personal = { ... }

Step 5: Add Dynamic Request Maps

The request maps class was generated in Step 2 and used to limit access by defining the access control at the URL. Here I create the request map in BootStrap.groovy for demo purpose, in your actual application this may be defined in configuration file or database. I don’t think you should choose between using annotation and request map. You can strike balance by implementing both to handle general and fine-grain access control.

import org.xaab.qotd.*

class BootStrap {
    def springSecurityService

    def init = { servletContext ->
		new Requestmap(url: '/**', configAttribute: 'IS_AUTHENTICATED_FULLY').save()
		new Requestmap(url: '/quote/**', configAttribute: 'ROLE_ADMIN,IS_AUTHENTICATED_FULLY').save()

		new Requestmap(url: '/js/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/css/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/images/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/ext-4.0.2/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/quote/random', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/login/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
		new Requestmap(url: '/logout/**', configAttribute: 'IS_AUTHENTICATED_ANONYMOUSLY').save()
    def destroy = {

Step 6: Amend related GSP to add login and logout link

Amend related GSP (random.gsp) to ensure you have the login and logout link. Since I used scaffolding, I must install the templates and ensure the GSP templates are modified.  Once scaffolding templates are installed, you will see the folders /src/templates/scaffolding/**. The files I modified in this sample application are create.gsp, edit.gsp, list.gsp & show.gsp.

<div class="nav"><span class="menuButton">Next Quote</span> <span class="menuButton">Admin</span> <span class="menuButton">Login</span> <span class="menuButton"> (Logout)</span></div>

Step 7: Customize the auth.gsp to Add ExtJs Login Form

By now the integration is completed and if you used the test data in Step 10, you will be able to see the default login page. In order to customize it, copy the ExtJS source into /web-app and in this sample application I am using ExtJS 4.0.2. Start the customization by modifying the auth.gsp as shown below. Do take note on the naming of the fields as it is the convention used in Spring Security.

Login<script type="text/javascript" src="${resource(dir:'ext-4.0.2',file:'ext-all.js')}"></script><script type="text/javascript">// <![CDATA[
		var defLoginUrl = '${postUrl}';
		var homeUrl = '${createLink(uri: "/quote/random")}';

// ]]></script>
<script type="text/javascript">// <![CDATA[

	var loginForm = Ext.create('Ext.form.Panel',{
			url: defLoginUrl,
			title: 'Login',
			renderTo: 'login',
			frame: true,
			cls: 'my-form-class',
			width: 350,
			items: [{
					xtype: 'textfield',
					fieldLabel: 'Login',
					name: 'j_username'
					xtype: 'textfield',
					inputType: 'password',
					fieldLabel: 'Password',
					name: 'j_password'
			}, {
				xtype: 'checkbox',
				fieldLabel: 'Remember Me?',
				name: '_spring_security_remember_me',
				checked: false
			buttons: [{
					id: 'lf.btn.login',
					text: 'Login',
					handler: function() {
					id: 'lf.btn.reset',
					text: 'Reset',
					handler: function() {


function fnLoginForm(theForm)
		success: function(form, action) {
			Ext.Msg.alert('Success', 'Login Successful!', function(btn, text) {
				if (btn == 'ok') {
					window.location = homeUrl; //optionally this can be part of the data return by the server.
		failure: function(form, action) {
			Ext.Msg.alert('Warning', action.result.error);
} //end fnLoginForm

function fnResetForm(theForm)
} //end fnResetForm
// ]]></script>

Step 8: Configure Authentication Success and Failure Handler

The ExtJS login form will perform HTTP post to submit the login data however it expects JSON data as response. The default method in the LoginController will not be able to handle this, thus you must define your own handler. Add your handler into Config.groovy as shown below. The handlers are implemented in LoginController in the next step.

grails.plugins.springsecurity.successHandler.defaultTargetUrl = '/login/authSucccessExtJs'
grails.plugins.springsecurity.successHandler.alwaysUseDefault = true
grails.plugins.springsecurity.failureHandler.defaultFailureUrl = '/login/authFailExtJs?login_error=1'

Step 9: Implement the Handler in LoginController

After adding the handler, I suggest you remove or comment out the other methods to ensure they are not accessible.

import grails.converters.JSON

import javax.servlet.http.HttpServletResponse

import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

import as SCH

class LoginController {

	 * Dependency injection for the authenticationTrustResolver.
	def authenticationTrustResolver

	 * Dependency injection for the springSecurityService.
	def springSecurityService
	 * The ExtJS Authentication success handler
	def authSucccessExtJs = {
		render([success: true, username:] as JSON)

	 * The ExtJS Authentication failure handler
	def authFailExtJs = {
			def username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
			String msg = ''
			def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
			if (exception) {
				if (exception instanceof AccountExpiredException) {
					msg = SpringSecurityUtils.securityConfig.errors.login.expired
				else if (exception instanceof CredentialsExpiredException) {
					msg = SpringSecurityUtils.securityConfig.errors.login.passwordExpired
				else if (exception instanceof DisabledException) {
					msg = SpringSecurityUtils.securityConfig.errors.login.disabled
				else if (exception instanceof LockedException) {
					msg = SpringSecurityUtils.securityConfig.errors.login.locked
				else {
					msg =

			render([success: false, error: msg] as JSON)

Step 10: Setup Test Data

So, you have integrated your Grails application, customized the login form using ExtJS. Now, setup the test data in BootStrap.groovy and launch the application (http://localhost:8080/grails-qotd-extjs).

import org.xaab.qotd.*

class BootStrap {
    def springSecurityService

    def init = { servletContext ->
		new Quote(author: "Unknown", content: "If you think sunshine brings you happiness, then you haven’t danced in the rain.").save()
		new Quote(author: "Lao Tzu", content: "An ant on the move does more than a dozing ox.").save()
		new Quote(author: "Tony Robbins", content: "It not knowing what to do, it’s doing what you know.").save()
		new Quote(author: "Bruce Lee", content: "Simplicity is the key to brilliance.").save()


		def userRole = Role.findByAuthority('ROLE_USER') ?: new Role(authority: 'ROLE_USER').save(failOnError: true)
		def adminRole = Role.findByAuthority('ROLE_ADMIN') ?: new Role(authority: 'ROLE_ADMIN').save(failOnError: true)

		def adminUser = User.findByUsername('admin') ?: new User(
			username: 'admin',
			password: springSecurityService.encodePassword('admin'),
			enabled: true).save(failOnError: true)

		if (!adminUser.authorities.contains(adminRole)) {
			UserRole.create(adminUser, adminRole)
    def destroy = {

Hope this tutorial helps and happy coding!

download source


Display JSON Data using ExtJS 4 Store

I am sharing a short example of how to display JSON data using ExtJS 4 Store. In previous version of ExtJS, there is a small helper class call JsonStore which is used to simplify creation Stores from JSON data. In ExtJS 4 the class is no longer there. In this example, I am retrieving USGS data as JSON and display it in Grid as shown below.

USGS Data in Gri

As shown below in line 20, I use proxy of type JSONP in to retrieve the JSON data.

  Ext.define('UsgsList', {
    extend: '',
    fields: [
       {name: 'fid',       type: 'int'},
       {name: 'title',     type: 'string'},
       {name: 'description',  type: 'string'},
       {name: 'link',      type: 'string'},
       {name: 'pubDate',    type: 'date'},
       {name: 'lat',      type: 'string'},
       {name: 'long',      type: 'string'}
    idProperty: 'fid'

var store = Ext.create('', {
    id: 'store',
    model: 'UsgsList',
    proxy: {
       type: 'jsonp',
       url: '',
    extraParams: {
       q: 'select * from rss where url=""',
       format: 'json'
   reader: {
      root: 'query.results.item',

function renderTitle(value, p, record) {
   return Ext.String.format('<a href="{1}" target="_blank">{0}</a>',

var grid = Ext.create('Ext.grid.Panel', {
   width: 700,
   height: 500,
   title: 'USGS - M2.5+',
   store: store,
   loadMask: true,
   disableSelection: true,
   invalidateScrollerOnRefresh: false,
   viewConfig: {
     trackOver: false
   // grid columns
      xtype: 'rownumberer',
      width: 50,
      sortable: false
      id: 'title',
      text: "Title",
      dataIndex: 'title',
      flex: 1,
      renderer: renderTitle,
      sortable: false
      id: 'pubDate',
      text: "Published Date",
      dataIndex: 'pubDate',
      width: 130,
      renderer: Ext.util.Format.dateRenderer('n/j/Y g:i A'),
      sortable: true
   renderTo: Ext.getBody()

// trigger the data store load

Countdown to ExtJS 4

On the 16th Feb 2010 Sencha announced the availability of the first Ext JS 4 Developer Preview. Definitely an exciting news for the Ext JS developers, I can see from the comments in Sencha Blog that people cannot wait for the release. This is the biggest overhaul to the framework. For those who worry about migration, the team has taken that into consideration.

Ext JS 4 is completely sandboxed; there is no more native object augmentation or reliance on global variables. This means you can run Ext JS 4 alongside Ext JS 3 on the same page. To demonstrate this we’ve taken the best of both versions and combined them in a single page. We’ve used the Desktop example from Ext JS 3 and loaded Ext JS 4’s brand new charts alongside as if they were part of Desktop itself – check it out for yourself.

The second step is to provide as strong a legacy layer as possible to help you upgrade your Ext JS 3.x applications. We’re starting that today with the release of a detailed overview guide to the differences between the versions, and will update this as we continue our rollout. In addition to the guide we will be providing a legacy file that can be dropped in to an Ext JS 3.x application to help you upgrade your app. We’ll be expanding on both of these in another post very soon. – Sencha Blog

The following articles highlights the key features in Ext JS 4;

Ed Spencer from Sencha presented the introduction to Ext JS 4 and its architecture. You can see the slides below;

Last but not least, the examples and download is available;

Happy hacking!!