转自 http://loianegroner.com/2010/02/integrating-spring-security-with-extjs-login-page/
This tutorial will walk through how to configure ExtJS Login form (Ajax login form) instead of default Spring Security login.jsp.
Instead of using login.jsp from spring security, why do not use an ajax login form?
And How to integrate the ExtJS Login Form with Spring Security ?
You did try to do it, the user is successfully authenticated, but the user is not redirected to the application main page. How to fix this situation? How to make it work?
It does not matter if you set the default-target-url in applicationContext-security.xml, or set a redirect URL on server side. It will not work this way.
The issue is that ExtJS make Ajax calls, and no redirect will work on server side. You have to redirect it on the client side, which is the ExtJS/javascript code.
First, you need to create the login form. You can use the javascript code provided by ExtJS and you can modify it to work with spring security.
If you take a look at the login.jsp, you will see three key points:
That is what you need to customize to make ExtJS Login form works! But do not be too comfortable, there are some issues you need to fix to make it work perfectly.
Take a look how login.js looks like (after customization):
01 |
Ext.onReady( function (){ |
02 |
Ext.QuickTips.init(); |
03 |
04 |
// Create a variable to hold our EXT Form Panel. |
05 |
06 |
// Assign various config options as seen. |
07 |
var login = new Ext.FormPanel({ |
08 |
labelWidth:80, |
09 |
url: 'j_spring_security_check' , |
10 |
frame: true , |
11 |
title: 'Please Login' , |
12 |
13 |
defaultType: 'textfield' , |
14 |
width:300, |
15 |
height:150, |
16 |
monitorValid: true , |
17 |
// Specific attributes for the text fields for username / password. |
18 |
// The "name" attribute defines the name of variables sent to the server. |
19 |
20 |
items:[{ |
21 |
fieldLabel: 'Username' , |
22 |
name: 'j_username' , |
23 |
allowBlank: false |
24 |
},{ |
25 |
fieldLabel: 'Password' , |
26 |
27 |
name: 'j_password' , |
28 |
inputType: 'password' , |
29 |
allowBlank: false |
30 |
}], |
31 |
32 |
// All the magic happens after the user clicks the button |
33 |
buttons:[{ |
34 |
35 |
text: 'Login' , |
36 |
formBind: true , |
37 |
// Function that fires when user clicks the button |
38 |
handler: function (){ |
39 |
login.getForm().submit({ |
40 |
41 |
method: 'POST' , |
42 |
43 |
// Functions that fire (success or failure) when the server responds. |
44 |
// The server would actually respond with valid JSON, |
45 |
// something like: response.write "{ success: true}" or |
46 |
47 |
// response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}" |
48 |
// depending on the logic contained within your server script. |
49 |
// If a success occurs, the user is notified with an alert messagebox, |
50 |
51 |
// and when they click "OK", they are redirected to whatever page |
52 |
// you define as redirect. |
53 |
54 |
success: function (){ |
55 |
Ext.Msg.alert( 'Status' , 'Login Successful!' , function (btn, text){ |
56 |
57 |
if (btn == 'ok' ){ |
58 |
window.location = 'main.action' ; |
59 |
} |
60 |
}); |
61 |
62 |
}, |
63 |
64 |
// Failure function, see comment above re: success and failure. |
65 |
// You can see here, if login fails, it throws a messagebox |
66 |
// at the user telling him / her as much. |
67 |
68 |
failure: function (form, action){ |
69 |
if (action.failureType == 'server' ){ |
70 |
obj = Ext.util.JSON.decode(action.response.responseText); |
71 |
72 |
Ext.Msg.alert( 'Login Failed!' , obj.errors.reason); |
73 |
} else { |
74 |
Ext.Msg.alert( 'Warning!' , 'Authentication server is unreachable : ' + action.response.responseText); |
75 |
76 |
} |
77 |
login.getForm().reset(); |
78 |
} |
79 |
80 |
}); |
81 |
} |
82 |
}] |
83 |
}); |
84 |
85 |
login.render( 'login' ); |
86 |
87 |
}); |
If you make these changes and try to execute the application with a basic applicationContext-security.xml file, the user will be successfully authenticated, but is not going to be redirected.
What are we missing then?
You need to customize AuthenticationProcessingFilter class for spring security to perform actions on login.
The “onSuccessfulAuthentication” and “onUnsuccessfulAuthentication” methods need to return some JSON content. If user is successfully authenticated, then redirect to main page, otherwise, the application will show an error message.
This is MyAuthenticationProcessingFilter class:
01 |
package com.loiane.security; |
02 |
03 |
import java.io.IOException; |
04 |
import java.io.Writer; |
05 |
06 |
import javax.servlet.http.HttpServletRequest; |
07 |
import javax.servlet.http.HttpServletResponse; |
08 |
import javax.servlet.http.HttpServletResponseWrapper; |
09 |
10 |
import org.springframework.security.Authentication; |
11 |
import org.springframework.security.AuthenticationException; |
12 |
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter; |
13 |
14 |
public class MyAuthenticationProcessingFilter extends AuthenticationProcessingFilter { |
15 |
16 |
protected void onSuccessfulAuthentication(HttpServletRequest request, |
17 |
HttpServletResponse response, Authentication authResult) |
18 |
throws IOException { |
19 |
super .onSuccessfulAuthentication(request, response, authResult); |
20 |
21 |
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response); |
22 |
23 |
Writer out = responseWrapper.getWriter(); |
24 |
25 |
String targetUrl = determineTargetUrl( request ); |
26 |
out.write( "{success:true, targetUrl : \'" + targetUrl + "\'}" ); |
27 |
out.close(); |
28 |
29 |
} |
30 |
31 |
protected void onUnsuccessfulAuthentication( HttpServletRequest request, |
32 |
HttpServletResponse response, AuthenticationException failed ) |
33 |
throws IOException { |
34 |
35 |
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response); |
36 |
37 |
Writer out = responseWrapper.getWriter(); |
38 |
39 |
out.write( "{ success: false, errors: { reason: 'Login failed. Try again.' }}" ); |
40 |
out.close(); |
41 |
42 |
} |
43 |
44 |
} |
And this is how applicationContext-security.xml looks like :
01 |
<? xml version = "1.0" encoding = "UTF-8" ?> |
02 |
03 |
< beans xmlns = "http://www.springframework.org/schema/beans " |
04 |
xmlns:security = "http://www.springframework.org/schema/security " |
05 |
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance " |
06 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd |
07 |
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd "> |
08 |
09 |
< security:global-method-security /> |
10 |
11 |
< security:http auto-config = "false" entry-point-ref = "authenticationProcessingFilterEntryPoint" > |
12 |
< security:intercept-url pattern = "/index.jsp" filters = "none" /> |
13 |
< security:intercept-url pattern = "/*.action" access = "ROLE_USER" /> |
14 |
</ security:http > |
15 |
16 |
< bean id = "authenticationProcessingFilter" class = "com.loiane.security.MyAuthenticationProcessingFilter" > |
17 |
< security:custom-filter position = "AUTHENTICATION_PROCESSING_FILTER" /> |
18 |
< property name = "defaultTargetUrl" value = "/main.html" /> |
19 |
< property name = "authenticationManager" ref = "authenticationManager" /> |
20 |
</ bean > |
21 |
22 |
< security:authentication-manager alias = "authenticationManager" /> |
23 |
24 |
< bean id = "authenticationProcessingFilterEntryPoint" |
25 |
class = "org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint" > |
26 |
< property name = "loginFormUrl" value = "/index.jsp" /> |
27 |
< property name = "forceHttps" value = "false" /> |
28 |
</ bean > |
29 |
30 |
<!-- |
31 |
Usernames/Passwords are |
32 |
rod/koala |
33 |
dianne/emu |
34 |
scott/wombat |
35 |
peter/opal |
36 |
These passwords are from spring security app example |
37 |
--> |
38 |
< security:authentication-provider > |
39 |
< security:password-encoder hash = "md5" /> |
40 |
< security:user-service > |
41 |
< security:user name = "rod" password = "a564de63c2d0da68cf47586ee05984d7" authorities = "ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" /> |
42 |
< security:user name = "dianne" password = "65d15fe9156f9c4bbffd98085992a44e" authorities = "ROLE_USER,ROLE_TELLER" /> |
43 |
< security:user name = "scott" password = "2b58af6dddbd072ed27ffc86725d7d3a" authorities = "ROLE_USER" /> |
44 |
< security:user name = "peter" password = "22b5c9accc6e1ba628cedc63a72d57f8" authorities = "ROLE_USER" /> |
45 |
</ security:user-service > |
46 |
</ security:authentication-provider > |
47 |
</ beans > |
Now you can login using ExtJS login form.
I coded a sample application for this example. If you like it, you can download it from my GitHub: http://github.com/loiane/spring-security-extjs-login
Happy coding!