当填写完成登录表单提交后,首先会被对应的提交表单提起的过滤器进行拦截,这里过滤器的作用就是拦截登录表单提交验证请求,并根据相应的表单信息构造对应的登录凭证,这里来看看过滤器是如何构造相应的用户凭证。
package com.template.security.filter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 12-11-9
* Time: 下午10:00
*/
public class MultipleAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private List<AuthenticationTokenResolver> tokenResolvers = new ArrayList<AuthenticationTokenResolver>();
/**
* @param defaultFilterProcessesUrl the default value for <tt>filterProcessesUrl</tt>.
*/
protected MultipleAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
for (AuthenticationTokenResolver tokenResolver : tokenResolvers) {
if (tokenResolver.support(request)) {
Authentication authentication = tokenResolver.resolve(request);
return this.getAuthenticationManager().authenticate(authentication);
}
}
throw new UnsupportedOperationException("No authentication token resolver found!");
}
public void setTokenResolvers(List<AuthenticationTokenResolver> tokenResolvers) {
this.tokenResolvers = tokenResolvers;
}
}
package com.template.security.filter;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 12-11-9
* Time: 下午10:08
*/
public interface AuthenticationTokenResolver {
boolean support(HttpServletRequest request);
Authentication resolve(HttpServletRequest request);
}
package com.template.security.filter;
import com.template.utils.StringUtils;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 12-11-9
* Time: 下午10:27
*/
public abstract class AbstractAuthenticationTokenResolver implements AuthenticationTokenResolver {
protected String parameterName;
protected String parameterValue;
protected AbstractAuthenticationTokenResolver() {
}
protected AbstractAuthenticationTokenResolver(String parameterName) {
this.parameterName = parameterName;
}
@Override
public boolean support(HttpServletRequest request) {
String parameterValue = request.getParameter(parameterName);
if (StringUtils.isEmpty(parameterValue)) {
return false;
}
return parameterValue.equals(this.parameterValue);
}
@Override
public abstract Authentication resolve(HttpServletRequest request);
public void setParameterName(String parameterName) {
this.parameterName = parameterName;
}
public void setParameterValue(String parameterValue) {
this.parameterValue = parameterValue;
}
}
package com.template.security.filter;
import com.template.security.authentication.token.BackendAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 12-11-9
* Time: 下午10:29
*/
public class BackendAuthenticationTokenResolver extends AbstractAuthenticationTokenResolver {
protected BackendAuthenticationTokenResolver() {
super();
}
@Override
public Authentication resolve(HttpServletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
String captcha = request.getParameter("captcha");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new BackendAuthenticationToken(username, password, authorities, captcha);
}
}
package com.template.security.filter;
import com.template.security.authentication.token.ForendAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: Zhong Gang
* Date: 12-11-9
* Time: 下午10:29
*/
public class ForendAuthenticationTokenResolver extends AbstractAuthenticationTokenResolver {
protected ForendAuthenticationTokenResolver() {
super();
}
@Override
public Authentication resolve(HttpServletRequest request) {
String email = request.getParameter("email");
String phone = request.getParameter("phone");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new ForendAuthenticationToken(email, phone, authorities);
}
}
这里实现AbstractAuthenticationProcessingFilter接口的类MultipleAuthenticationProcessingFilter,用来根据相应的登录表单提交信息构造相应的登录用户凭证。为了实现根据前台登录表单信息构造前台用户凭证,根据后台登录表单信息构造后台用户凭证,使用了策略模式来实现,实现AbstractAuthenticationTokenResolver接口的BackendAuthenticationTokenResolver和ForendAuthenticationTokenResolver分别用来构造后台用户凭证和前台用户凭证,再来看看配置文件是如何进行配置的吧。
<beans:bean id="multipleAuthenticationProcessingFilter" class="com.template.security.filter.MultipleAuthenticationProcessingFilter"> <beans:constructor-arg value="/login/check"/> <beans:property name="tokenResolvers"> <beans:list> <beans:ref bean="backendAuthenticationTokenResolver"/> <beans:ref bean="forendAuthenticationTokenResolver"/> </beans:list> </beans:property> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="authenticationSuccessHandler" ref="multipleAuthenticationSuccessHandler"/> <beans:property name="authenticationFailureHandler" ref="multipleAuthenticationFailureHandler"/> </beans:bean> <beans:bean id="backendAuthenticationTokenResolver" class="com.template.security.filter.BackendAuthenticationTokenResolver"> <beans:property name="parameterName" value="token"/> <beans:property name="parameterValue" value="backend"/> </beans:bean> <beans:bean id="forendAuthenticationTokenResolver" class="com.template.security.filter.ForendAuthenticationTokenResolver"> <beans:property name="parameterName" value="token"/> <beans:property name="parameterValue" value="forend"/> </beans:bean>
这里不论是前台登录还是后台登录,都提交到相同的地址/login/check,不过为了区分请求到底是前台登录认证还是后台登录认证,这里使用了一个名为token的请求参数来区分,当token的值为backend的时候表明是后台登录认证,当token的值为forend的时候表明是前台登录认证。
<custom-filter ref="multipleAuthenticationProcessingFilter" before="FORM_LOGIN_FILTER"/>
这段配置表明自定义的认证过滤器将在Spring Security默认的UsernamePasswordAuthenticationFilter前执行,研究UsernamePasswordAuthenticationFilter源码你就会发现平时使用到的登录认证请求地址j_spring_security_check就是被这个过滤器进行拦截并进行处理的,所以如果只是简单的登录认证,你只需要在登录页面进行一些修改就完成可以了,因为后台的处理已经完全交由Spring Security来帮我们处理了。