(1). 概述

在这一篇,主要剖析当登录的时候,Spring Security是如可处理的,要剖析的源码就是上一小节,剖析时留下来的Filter(UsernamePasswordAuthenticationFilter)

(2). 看下UsernamePasswordAuthenticationFilter关系图

org.springframework.web.filter.GenericFilterBean   # GenericFilterBean是Spring对Filter的扩展
	org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
		org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

(3). AbstractAuthenticationProcessingFilter

我们知道,对于Filter应该要看doFilter方法,所以,AbstractAuthenticationProcessingFilter是对doFilter的实现,然后,预留一小部份给了:UsernamePasswordAuthenticationFilter

public abstract class AbstractAuthenticationProcessingFilter 
				// ***********************************************************************************
				// GenericFilterBean
				// ***********************************************************************************
                extends GenericFilterBean
				implements ApplicationEventPublisherAware, MessageSourceAware {

	// 把用户名和密码,变成:UsernamePasswordAuthenticationToken后,会回调:AuthenticationDetailsSource进行配置:UsernamePasswordAuthenticationToken的相关信息
	protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
	
	// ********************************************************************************************************
	// 2. 最终要委托给:AuthenticationManager
	// ********************************************************************************************************
	private AuthenticationManager authenticationManager;
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private RememberMeServices rememberMeServices = new NullRememberMeServices();

	private RequestMatcher requiresAuthenticationRequestMatcher;
    
	// 是否跳过成功后的回调函数
	private boolean continueChainBeforeSuccessfulAuthentication = false;

    // ***********************************************************************************************
	// Session管理策略(典型的策略模式)
	// ***********************************************************************************************
	private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

	private boolean allowSessionCreation = true;

    // ***************************************************************************************************
	// 登录成功/登录失败相应的Handler
	// ***************************************************************************************************
	private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
	private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
	
	
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
				throws IOException, ServletException {
					
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
        
		// 如果不是登录(/login)请求,则直接跳过Filter
		if (!requiresAuthentication(request, response)) {
			chain.doFilter(request, response);

			return;
		}
         
		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}

        // ***********************************************************************************
		// 认证之后的结果.
		// ***********************************************************************************
		Authentication authResult;

		try {
			// ***********************************************************************************
			// 委派给子类(UsernamePasswordAuthenticationFilter)进行处理
			// ***********************************************************************************
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			
			// 委托给Session管理策略,在这里我们暂且不管这个
			sessionStrategy.onAuthentication(authResult, request, response);
		} catch (InternalAuthenticationServiceException failed) {
			logger.error("An internal error occurred while trying to authenticate the user.",failed);
			// ***********************************************************************************
			// 认证失败的Handler
			// ***********************************************************************************
			unsuccessfulAuthentication(request, response, failed);
			return;
		} catch (AuthenticationException failed) {
			// ***********************************************************************************
			// 认证失败的Handler
			// ***********************************************************************************
			// Authentication failed
			unsuccessfulAuthentication(request, response, failed);
			return;
		}

        // 可开关配置,是否启用认证成功的Filter
		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}

		// ***********************************************************************************
		// 认证成功的Handler
		// ***********************************************************************************
		successfulAuthentication(request, response, chain, authResult);
	} // end doFilter
	
	protected void successfulAuthentication(HttpServletRequest request,
				HttpServletResponse response, FilterChain chain, Authentication authResult)
				throws IOException, ServletException {
	
		if (logger.isDebugEnabled()) {
			logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
					+ authResult);
		}

		// ***********************************************************************************
		// 认证成功之后,把Authentication与线程上下文进行绑定.
		// ***********************************************************************************
		SecurityContextHolder.getContext().setAuthentication(authResult);
		
		// ***********************************************************************************
		// 调用记住我功能
		// ***********************************************************************************
		rememberMeServices.loginSuccess(request, response, authResult);

		// Fire event
		if (this.eventPublisher != null) {
			eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
					authResult, this.getClass()));
		}

		successHandler.onAuthenticationSuccess(request, response, authResult);
	} // end successfulAuthentication
	
}

(4). UsernamePasswordAuthenticationFilter

public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
	public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

	private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
	private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
	private boolean postOnly = true;
    
	
	public UsernamePasswordAuthenticationFilter() {
		// 设置登录的URLMatcher
		super(new AntPathRequestMatcher("/login", "POST"));
	}
	
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
		
		// 如果,不是POST请求,则抛出异常(AuthenticationServiceException)
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
		}
		
		// 从请求中获得用户名和密码
		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();

		// ********************************************************************************************
		// 产生Authentication(UsernamePasswordAuthenticationToken)
		// ********************************************************************************************
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

		// ********************************************************************************************
		// 调用父类,设置:Authentication的一些相关信息
		// ********************************************************************************************
		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);

		// ********************************************************************************************
		// 委托给:AuthenticationManager进行认证管理
		// ********************************************************************************************
		return this.getAuthenticationManager().authenticate(authRequest);
	} // end attemptAuthentication
}

(5). 总结

UsernamePasswordAuthenticationFilter的主要职责就是把登录表单的信息,封装成:Authentication,并委派给:AuthenticationManager进行处理,最后把认证成功后的对象:Authentication与线程上下文进行绑定.