Integrando Spring Security com a página de Login do ExtJS

1 de February de 2010 | By | 13 Comments

Esse tutorial irá abordar como configurar o form de login da biblioteca ExtJS (Ajax) ao invés de utilizar a página de login (login.jsp) padrão do Spring Security..

Em vez de usar a página de login do Spring Security, por que não usar um form feito com Ajax?

E como integrar a página de login do ExtJS com o framework Spring Security?

Ok, você já tentou fazer isso, o usuário foi autenticado com sucesso, mas o usuário não é redirecionado para a página principal da aplicação. Como consertar isso?

Não importa de você setou a opção default-target-url no arquivo applicationContext-security.xml, ou setou uma URL para redirecionamento no lado do servidor. Não vai funcionar.

O problema é que o ExtJS faz uma chamada/request Ajax, e nenhum redirecionamento irá funcionar no lado servidor (spring). Você deve fazer esse redirecionamento no lado cliente, que é no código ExtJS/javascript.

Primeiro, você precisa crier o form do login. Você pode utilizar o código de exemplo disponibilizado pelo ExtJS: http://www.extjs.com/learn/Tutorial:Basic_Login e customizá-lo/modificá-lo para funcinoar com o Spring Security.

Se der uma olhada no arquivo login.jsp (padrão do Spring Security), você irá perceber três pontos chaves do form:

  1. URL / form action: j_spring_security_check
  2. Username input name: j_username
  3. Password input name: j_password

É isso que precisa customizar no login do ExtJS para fazê-lo funcinar com o Spring Security. Mas não pense que é assim tão fácil, ainda tem um pequeno detalhe que precisa consertar para funcionar perfeitamente.

O login.js irá ficar assim após as moficações:

Ext.onReady(function(){
	Ext.QuickTips.init();

	// Create a variable to hold our EXT Form Panel.

	// Assign various config options as seen.
	var login = new Ext.FormPanel({
		labelWidth:80,
		url:'j_spring_security_check',
		frame:true,
		title:'Please Login',

		defaultType:'textfield',
		width:300,
		height:150,
		monitorValid:true,
		// Specific attributes for the text fields for username / password.
		// The "name" attribute defines the name of variables sent to the server.

		items:[{
			fieldLabel:'Username',
			name:'j_username',
			allowBlank:false
		},{
			fieldLabel:'Password',

			name:'j_password',
			inputType:'password',
			allowBlank:false
		}],

		// All the magic happens after the user clicks the button
		buttons:[{

			text:'Login',
			formBind: true,
			// Function that fires when user clicks the button
			handler:function(){
			login.getForm().submit({

				method:'POST',

				// Functions that fire (success or failure) when the server responds.
				// The server would actually respond with valid JSON,
				// something like: response.write "{ success: true}" or

				// response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}"
				// depending on the logic contained within your server script.
				// If a success occurs, the user is notified with an alert messagebox,

				// and when they click "OK", they are redirected to whatever page
				// you define as redirect.

				success:function(){
				Ext.Msg.alert('Status', 'Login Successful!', function(btn, text){

					if (btn == 'ok'){
						window.location = 'main.action';
					}
				});

			},

			// Failure function, see comment above re: success and failure.
			// You can see here, if login fails, it throws a messagebox
			// at the user telling him / her as much.

			failure:function(form, action){
				if(action.failureType == 'server'){
					obj = Ext.util.JSON.decode(action.response.responseText);

					Ext.Msg.alert('Login Failed!', obj.errors.reason);
				}else{
					Ext.Msg.alert('Warning!', 'Authentication server is unreachable : ' + action.response.responseText);

				}
				login.getForm().reset();
			}

			});
		}
		}]
	});

	login.render('login');

});

O que está faltando?

É necessário customizar a classe AuthenticationProcessingFilter para o Spring Security executar a ação no login.

Os métodos “onSuccessfulAuthentication” e “onUnsuccessfulAuthentication” precisam retornar algum conteúdo JSON. Se o usuário for autenticado com sucesso, então redireciona-o para a página principal da aplicação, senão, a aplicação irá mostrar uma mensagem de erro.

Essa é a classe MyAuthenticationProcessingFilter customizada:

package com.loiane.security;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;

public class MyAuthenticationProcessingFilter extends AuthenticationProcessingFilter {

	protected void onSuccessfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, Authentication authResult)
	throws IOException {
		super.onSuccessfulAuthentication(request, response, authResult);

		HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response);

		Writer out = responseWrapper.getWriter();

		String targetUrl = determineTargetUrl( request );
		out.write("{success:true, targetUrl : \'" + targetUrl + "\'}");
		out.close();

	}

	protected void onUnsuccessfulAuthentication( HttpServletRequest request,
			HttpServletResponse response, AuthenticationException failed )
	throws IOException {

		HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response);

		Writer out = responseWrapper.getWriter();

		out.write("{ success: false, errors: { reason: 'Login failed. Try again.' }}");
		out.close();

	}

}

E o arquivo applicationContext-security.xml ficará assim:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:security="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">

	<security:global-method-security />

	<security:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
		<security:intercept-url pattern="/index.jsp" filters="none" />
		<security:intercept-url pattern="/*.action" access="ROLE_USER" />
	</security:http>

	<bean id="authenticationProcessingFilter" class="com.loiane.security.MyAuthenticationProcessingFilter">
		<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
		<property name="defaultTargetUrl" value="/main.html" />
		<property name="authenticationManager" ref="authenticationManager" />
	</bean>

	<security:authentication-manager alias="authenticationManager" />

	<bean id="authenticationProcessingFilterEntryPoint"
		class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
		<property name="loginFormUrl" value="/index.jsp" />
		<property name="forceHttps" value="false" />
	</bean>

    <!--
    Usernames/Passwords are
        rod/koala
        dianne/emu
        scott/wombat
        peter/opal
    These passwords are from spring security app example
    -->
    <security:authentication-provider>
        <security:password-encoder hash="md5"/>
        <security:user-service>
            <security:user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <security:user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <security:user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <security:user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
	    </security:user-service>
	</security:authentication-provider>
</beans>

Agora irá logar normalmente com o form de login do ExtJS.

Fiz uma pequena aplicação de exemplo. Se desejar, pode fazer o download do meu repositório no GitHub: http://github.com/loiane/spring-security-extjs-login

Bons códigos!

Posts Similares

Filed in: Ext JS 3, Spring, Spring Security | Tags: , , , ,

Comments (13)

Links to this Post

  1. Retrospectiva 2010 | Loiane Groner | 23 de December de 2010
  1. Seu blog é mto show, muitos tutos interessantes sobre extjs, bacana demais, fiquei conhecendo hoje, estou impressionado.

    Parabéns !

  2. Loiane,

    Como sempre seu blog me ajudando. Estou querendo fazer exatamente a mesma coisa que vc fez. Mas com spring security 3.0 O filtro que tenho que implementar no spring 3 seria o UsernamePasswordAuthenticationFilter? Estou tendo alguns problemas com isso. Pode me ajudar?

  3. Opa Loiane tudo bom!

    Bacana o tutor mais como seria feito com a nova versão do Extjs 4?

    abraço e sucesso!

  4. Oi Simão,
    Em breve colocarei alguns tutoriais com Ext JS 4 aqui no blog!
    Também estou preparando uma série de posts com Spring Security 3, mas está em stand by por conta do livro!
    []‘s

  5. Boa Noite Loiane, consergui fazer usando a nova versão do extjs 4utilizando sua arquitetura MVC. Logo Mais vou posta no meu blog….. ssucesso.!

  6. Ei Simão, bacana!
    Posta aqui o link depois pro pessoal usar como referência tb!
    []‘s

  7. Opa Loiane! Boa tarde turma como tinha falado antes fiz o exemplo de login extjs4 e spring security não foi nada muito complicado pois tive uma boa referencia que é o exemplo da Loiane usando a versão 3 do extjs e spring security, estou colocando apenas o link do git depois coloco no meu blog.

    https://github.com/tryonn/Java-Extjs

  8. ari

    Loiane, vc jah fez este formulário com remember-me? esse filtro nao funciona pq ele fecha o response… tem idéia dq dá pra fazer? acho que é a posicao do filtro do remember-me, mas nao consigo arrumar isso… valeu demais!

  9. Olá Ari,
    Existe um plugin feito por terceiros para isso, mas aí não dá pra fazer via Ajax, como nesse exemplo.
    Vou ver se posto o exemplo aqui.
    []‘s

  10. Amiga, sou programador Delphi, mas gostei do resultado que o ExtJs proporciona. Pergunto: quem ou onde eu poderia obter um bom treinamento nessa ferramenta ?

    Obrigado

  11. Olá Israel,
    Aqui no blog estou disponibilizando um curso totalmente gratuito do ExtJS 4: http://www.loiane.com/2011/11/curso-de-extjs-4-gratuito/
    []‘s

Leave a Reply

Trackback URL | RSS Feed for This Entry