这也是为什么spring security第2+N次登陆都不会跑default_target_url的原因,解决这个问题在于要让internet识别这是不同的请求,最简单的做法便是在URL上加一个随机的参数。所以我复写了AuthenticationProcessingFilter这个方法:
public class MyAuthenticationProcessingFilter extends AbstractProcessingFilter { //~ Static fields/initializers ===================================================================================== public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password"; public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME"; private boolean useRelativeContext = false; private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; //~ Methods ======================================================================================================== public Authentication attemptAuthentication(HttpServletRequest request) throws AuthenticationException { String username = obtainUsername(request); String password = obtainPassword(request); if (username == null) { username = ""; } if (password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Place the last username attempted into HttpSession for views HttpSession session = request.getSession(false); if (session != null || getAllowSessionCreation()) { request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextUtils.escapeEntities(username)); } // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * This filter by default responds to <code>/j_spring_security_check</code>. * * @return the default */ public String getDefaultFilterProcessesUrl() { return "/j_spring_security_check"; } /** * Enables subclasses to override the composition of the password, such as by including additional values * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p> * * @param request so that request attributes can be retrieved * * @return the password that will be presented in the <code>Authentication</code> request token to the * <code>AuthenticationManager</code> */ protected String obtainPassword(HttpServletRequest request) { return request.getParameter(passwordParameter); } /** * Enables subclasses to override the composition of the username, such as by including additional values * and a separator. * * @param request so that request attributes can be retrieved * * @return the username that will be presented in the <code>Authentication</code> request token to the * <code>AuthenticationManager</code> */ protected String obtainUsername(HttpServletRequest request) { return request.getParameter(usernameParameter); } /** * Provided so that subclasses may configure what is put into the authentication request's details * property. * * @param request that an authentication request is being created for * @param authRequest the authentication request object that should have its details set */ protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } /** * Sets the parameter name which will be used to obtain the username from the login request. * * @param usernameParameter the parameter name. Defaults to "j_username". */ public void setUsernameParameter(String usernameParameter) { Assert.hasText(usernameParameter, "Username parameter must not be empty or null"); this.usernameParameter = usernameParameter; } /** * Sets the parameter name which will be used to obtain the password from the login request.. * * @param passwordParameter the parameter name. Defaults to "j_password". */ public void setPasswordParameter(String passwordParameter) { Assert.hasText(passwordParameter, "Password parameter must not be empty or null"); this.passwordParameter = passwordParameter; } public int getOrder() { return FilterChainOrder.AUTHENTICATION_PROCESSING_FILTER; } String getUsernameParameter() { return usernameParameter; } String getPasswordParameter() { return passwordParameter; } protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException { String finalUrl; if (!url.startsWith("http://") && !url.startsWith("https://")) { if (useRelativeContext) { finalUrl = url; } else { finalUrl = request.getContextPath() + url; } } else if (useRelativeContext) { // Calculate the relative URL from the fully qualifed URL, minus the protocol and base context. int len = request.getContextPath().length(); int index = url.indexOf(request.getContextPath()) + len; finalUrl = url.substring(index); if (finalUrl.length() > 1 && finalUrl.charAt(0) == '/') { finalUrl = finalUrl.substring(1); } } else { finalUrl = url; } //response.setHeader("Location", response.encodeRedirectURL(finalUrl)); //往URL加上时间戳作为随机数 if(finalUrl.indexOf("?")>=0) finalUrl = finalUrl+"&randomkey="+new Date().getTime(); else finalUrl = finalUrl+"?randomkey="+new Date().getTime(); response.sendRedirect(response.encodeRedirectURL(finalUrl)); } }
相应地xml配置修改:
<bean id="authenticationProcessingFilter" class="com.portal.security.authorities.filter.MyAuthenticationProcessingFilter"> <property name="defaultTargetUrl" value="/portal/forward.gm"></property> <property name="filterProcessesUrl" value="/security_login.gm"></property> <property name="authenticationManager" ref="authenticationManager"></property> <property name="alwaysUseDefaultTargetUrl" value="true"></property> <property name="authenticationFailureUrl" value="/portal/signin.gm?error=true"></property> <property name="rememberMeServices" ref="rememberMeServices" /> </bean>