天天看點

Spring Security Web 5.1.2 源碼解析 -- UsernamePasswordAuthenticationFilter概述源代碼解析參考文章

概述

該過濾器會攔截使用者請求,看它是否是一個來自使用者名/密碼表單登入頁面送出的使用者登入認證請求,預設使用的比對模式是:

POST /login

。預設情況下,如果是使用者登入認證請求,該請求就不會在整個

filter chain

中繼續傳遞了,而是會被目前過濾器處理并進入響應使用者階段。

具體使用者登入認證處理邏輯是這樣的,它會調用所指定的

AuthenticationManager

認證所送出的使用者名/密碼。

如果認證成功,則會 :

  1. 調用所設定的

    SessionAuthenticationStrategy

    會話認證政策;
    針對

    Servlet 3.1+

    ,預設所使用的

    SessionAuthenticationStrategy

    是一個

    ChangeSessionIdAuthenticationStrategy

    CsrfAuthenticationStrategy

    組合。

    ChangeSessionIdAuthenticationStrategy

    會為登入的使用者建立一個新的

    session

    ,而

    CsrfAuthenticationStrategy

    會建立新的

    csrf token

    用于

    CSRF

    保護。
  2. 經過完全認證的

    Authentication

    對象設定到

    SecurityContextHolder

    中的

    SecurityContext

    上;
  3. 如果請求要求了

    Remember Me

    ,進行相應記錄;
  4. 釋出事件

    InteractiveAuthenticationSuccessEvent

    ;
  5. 擷取并跳轉到目标跳轉頁面;
    預設情況下,該跳轉政策是

    SavedRequestAwareAuthenticationSuccessHandler

    • 如果有儲存的請求,則擷取儲存的請求,跳轉到相應的請求位址;
      一般在未登入使用者直接通路受保護頁面時會出現該情況:先被跳轉到登入頁面,登入完成過後再被跳轉到原始請求頁面
    • alwaysUseDefaultTargetUrl

      true

      則總是會跳到指定的

      defaultTargetUrl

      ;
      注意:

      defaultTargetUrl

      也是可以設定的,如果不設定,其值預設為

      /

    • alwaysUseDefaultTargetUrl

      false

      • 看請求參數中是否含有名稱為配置參數

        targetUrlParameter

        值的參數,如果有,跳轉到它定義的位址;
      • 否則如果指定了

        useReferer

        ,嘗試使用請求頭部

        Referer

        作為目标跳轉位址;
      • 否則使用

        defaultTargetUrl

        作為目标跳轉位址;

源代碼解析

package org.springframework.security.web.authentication;

import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;

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

public class UsernamePasswordAuthenticationFilter extends
		AbstractAuthenticationProcessingFilter {
	// ~ Static fields/initializers
	// =====================================================================================

	// 使用者名/密碼登入表單中使用者名字段預設使用的名稱
	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;

	// ~ Constructors
	// ===================================================================================================

	public UsernamePasswordAuthenticationFilter() {
		// 預設比對使用者請求 POST /login,認為該請求是使用者名/密碼表單登入驗證請求
		super(new AntPathRequestMatcher("/login", "POST"));
	}

	// ~ Methods
	// ========================================================================================================

	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		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 = "";
		}

		// 注意,這裡對使用者名做了trim操作,一般了解,就是去除了前後的空格
		username = username.trim();

		// 根據使用者提供的使用者名/密碼資訊建構一個認證token
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);

		// 交給 authenticationManager執行真正的使用者身份認證
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	/**
	 * 從請求參數中擷取密碼
	 * 
	 * Enables subclasses to override the composition of the password, such as by
	 * including additional values and a separator.
	 * 
	 * 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 AuthenticationDao will need to
	 * generate the expected password in a corresponding manner.
	 * 
	 *
	 * @param request so that request attributes can be retrieved
	 *
	 * @return the password that will be presented in the Authentication
	 * request token to the AuthenticationManager
	 */
	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 Authentication
	 * request token to the AuthenticationManager
	 */
	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.
	 * 指定從使用者名/密碼登入認證表單中擷取使用者名時使用的屬性名稱,預設為 username 
	 * @param usernameParameter the parameter name. Defaults to "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..
	 * 指定從使用者名/密碼登入認證表單中擷取使用者名時使用的屬性名稱,預設為 password
	 * @param passwordParameter the parameter name. Defaults to "password".
	 */
	public void setPasswordParameter(String passwordParameter) {
		Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
		this.passwordParameter = passwordParameter;
	}

	/**
	 * Defines whether only HTTP POST requests will be allowed by this filter. If set to
	 * true, and an authentication request is received which is not a POST request, an
	 * exception will be raised immediately and authentication will not be attempted. The
	 * unsuccessfulAuthentication() method will be called as if handling a failed
	 * authentication.
	 * 
	 * 設定是否僅僅接受HTTP POST使用者名/密碼登入驗證表單請求,預設為true,表示必須使用HTTP POST。
	 * 
	 * Defaults to true but may be overridden by subclasses.
	 */
	public void setPostOnly(boolean postOnly) {
		this.postOnly = postOnly;
	}

	public final String getUsernameParameter() {
		return usernameParameter;
	}

	public final String getPasswordParameter() {
		return passwordParameter;
	}
}

           

UsernamePasswordAuthenticationFilter

繼承自

AbstractAuthenticationProcessingFilter

:

package org.springframework.security.web.authentication;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * Abstract processor of browser-based HTTP-based authentication requests.
 * 基于浏覽器和HTTP的認證請求的處理抽象。
 *
 * Authentication Process 認證過程
 *
 * The filter requires that you set the authenticationManager property. An
 * AuthenticationManager is required to process the authentication request tokens
 * created by implementing classes.
 * 該過濾器執行認證需要一個authenticationManager,這個AuthenticationManager用來針對
 * 所建立的認證請求token做真正的使用者身份認證動作。
 * 
 * This filter will intercept a request and attempt to perform authentication from that
 * request if the request matches the
 * #setRequiresAuthenticationRequestMatcher(RequestMatcher).
 * 該過濾器攔截請求識别目前請求是否一個使用者名/密碼表單認證請求的比對方法是通過方法
 * #setRequiresAuthenticationRequestMatcher(RequestMatcher)指定的一個RequestMatcher。
 * 
 * Authentication is performed by the
 * #attemptAuthentication(HttpServletRequest, HttpServletResponse)
 * method, which must be implemented by subclasses.
 * 認證動作由方法#attemptAuthentication(HttpServletRequest, HttpServletResponse)完成,
 * 該方法由子類實作。上面的UsernamePasswordAuthenticationFilter就提供了該方法的實作。
 *
 * Authentication Success 認證成功
 *
 * If authentication is successful, the resulting Authentication object will be
 * placed into the SecurityContext for the current thread, which is
 * guaranteed to have already been created by an earlier filter.
 * 認證成功時,結果認證對象Authentication會被放到一個SecurityContext對象中,然後儲存在處理
 * 目前請求的線程中。
 * 
 * The configured #setAuthenticationSuccessHandler(AuthenticationSuccessHandler)
 * will then be called to take the redirect to the
 * appropriate destination after a successful login. The default behaviour is implemented
 * in a SavedRequestAwareAuthenticationSuccessHandler which will make use of any
 * DefaultSavedRequest set by the ExceptionTranslationFilter and
 * redirect the user to the URL contained therein. Otherwise it will redirect to the
 * webapp root "/". You can customize this behaviour by injecting a differently configured
 * instance of this class, or by using a different implementation.
 * 然後通過#setAuthenticationSuccessHandler(AuthenticationSuccessHandler)所設定的
 * AuthenticationSuccessHandler會被調用,進而頁面被跳轉到所配置的成功登入頁面。
 * 
 * Authentication Failure 認證失敗
 *
 * If authentication fails, it will delegate to the configured
 * AuthenticationFailureHandler to allow the failure information to be conveyed to
 * the client. The default implementation is SimpleUrlAuthenticationFailureHandler
 * , which sends a 401 error code to the client. It may also be configured with a failure
 * URL as an alternative. Again you can inject whatever behaviour you require here.
 * 如果認證失敗,該過濾器會代理給AuthenticationFailureHandler将失敗資訊傳回給客戶。預設實作是
 * 一個SimpleUrlAuthenticationFailureHandler,它會發送一個HTTP 401代碼給用戶端。
 * 
 * Event Publication 事件釋出
 *
 * If authentication is successful, an InteractiveAuthenticationSuccessEvent will
 * be published via the application context. No events will be published if authentication
 * was unsuccessful, because this would generally be recorded via an
 * AuthenticationManager-specific application event.
 * 認證成功時一個InteractiveAuthenticationSuccessEvent事件會釋出到應用上下文。認證不成功
 * 則不會釋出任何事件。
 *
 * Session Authentication
 *
 * The class has an optional SessionAuthenticationStrategy which will be invoked
 * immediately after a successful call to attemptAuthentication(). Different
 * implementations
 * #setSessionAuthenticationStrategy(SessionAuthenticationStrategy) can be
 * injected to enable things like session-fixation attack prevention or to control the
 * number of simultaneous sessions a principal may have.
 *
 * @author Ben Alex
 * @author Luke Taylor
 */
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
	// ~ Static fields/initializers
	// =====================================================================================

	// ~ Instance fields
	// ================================================================================================

	protected ApplicationEventPublisher eventPublisher;
	protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = 
		new WebAuthenticationDetailsSource();
	// 真正執行認證的認真管理器
	private AuthenticationManager authenticationManager;
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private RememberMeServices rememberMeServices = new NullRememberMeServices();

	private RequestMatcher requiresAuthenticationRequestMatcher;

	// 登入認證成功時是否繼續執行filter chain,預設為false,該屬性安全配置階段會重新指定,
	// 但安全配置階段預設使用的值也是false,表示登入認證成功時不繼續執行filter chain,而是
	// 由該頁面直接進入響應使用者階段
	private boolean continueChainBeforeSuccessfulAuthentication = false;

	// session 認證政策
	// 安全配置中預設是一個 CompositeSessionAuthenticationStrategy 對象,應用了組合模式,組合一些其他的
	// session 認證政策實作,比如針對Servlet 3.1+,預設會是 ChangeSessionIdAuthenticationStrategy跟
	// CsrfAuthenticationStrategy組合
	// 這裡雖然初始化為NullAuthenticatedSessionStrategy,但它會被安全配置中的值覆寫
	private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

	private boolean allowSessionCreation = true;

	private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
	private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

	// ~ Constructors
	// ===================================================================================================

	/**
	 * @param defaultFilterProcessesUrl the default value for <tt>filterProcessesUrl</tt>.
	 */
	protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
		setFilterProcessesUrl(defaultFilterProcessesUrl);
	}

	/**
	 * Creates a new instance
	 *
	 * @param requiresAuthenticationRequestMatcher the {@link RequestMatcher} used to
	 * determine if authentication is required. Cannot be null.
	 */
	protected AbstractAuthenticationProcessingFilter(
			RequestMatcher requiresAuthenticationRequestMatcher) {
		Assert.notNull(requiresAuthenticationRequestMatcher,
				"requiresAuthenticationRequestMatcher cannot be null");
		this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
	}

	// ~ Methods
	// ========================================================================================================

	@Override
	public void afterPropertiesSet() {
		Assert.notNull(authenticationManager, "authenticationManager must be specified");
	}


	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (!requiresAuthentication(request, response)) {
			// 檢查目前請求是否是一個使用者名/密碼登入表單請求,如果不是,則繼續執行filter chain
			// 的其他部分
			chain.doFilter(request, response);

			return;
		}

		// 下面是檢測到這是一個使用者名/密碼登入表單請求時的處理邏輯
		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}

		Authentication authResult;

		try {
			// 交給 AuthenticationManger 執行相應的認證
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			//針對Servlet 3.1+,預設所使用的SessionAuthenticationStrategy會是一個
			//ChangeSessionIdAuthenticationStrategy和CsrfAuthenticationStrategy組合。
			//ChangeSessionIdAuthenticationStrategy會為登入的使用者建立一個新的session,
			//而CsrfAuthenticationStrategy會建立新的csrf token用于CSRF保護。
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
			// 認證失敗		
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			// 認證失敗
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// Authentication success
		// 認證成功,如果continueChainBeforeSuccessfulAuthentication為true,
		// (continueChainBeforeSuccessfulAuthentication預設為false)
		// 繼續執行filter chain的其他部分
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}

		// 認證成功後的處理邏輯
		successfulAuthentication(request, response, chain, authResult);
	}

	/**
	 * 檢測目前請求是否是登入認證請求
	 * Indicates whether this filter should attempt to process a login request for the
	 * current invocation.
	 * 
	 * It strips any parameters from the "path" section of the request URL (such as the
	 * jsessionid parameter in http://host/myapp/index.html;jsessionid=blah)
	 * before matching against the filterProcessesUrl property.
	 * 
	 * Subclasses may override for special requirements, such as Tapestry integration.
	 *
	 * @return true if the filter should attempt authentication,
	 * false otherwise.
	 */
	protected boolean requiresAuthentication(HttpServletRequest request,
			HttpServletResponse response) {
		return requiresAuthenticationRequestMatcher.matches(request);
	}

	/**
	 * Performs actual authentication. 執行真正的認證
	 * 
	 * The implementation should do one of the following:
	 * 會是以下三種情況之一:
	 * 
	 * 1.Return a populated authentication token for the authenticated user, indicating
	 * successful authentication 認證成功,填充認證了的使用者的其他資訊到authentication token并傳回之
	 * 2.Return null, indicating that the authentication process is still in progress.
	 * Before returning, the implementation should perform any additional work required to
	 * complete the process.傳回null表示認證仍在進行中。
	 * 3.Throw an AuthenticationException if the authentication process fails。抛出一個
	 * 異常AuthenticationException表示認證失敗。
	 * 
	 *
	 * @param request from which to extract parameters and perform the authentication
	 * @param response the response, which may be needed if the implementation has to do a
	 * redirect as part of a multi-stage authentication process (such as OpenID).
	 *
	 * @return the authenticated user token, or null if authentication is incomplete.
	 *
	 * @throws AuthenticationException if authentication fails.
	 */
	public abstract Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException, IOException,
			ServletException;

	/**
	 * Default behaviour for successful authentication.認證成功時的預設行為。
	 * 
	 * 1. Sets the successful Authentication object on the SecurityContextHolder
	 * 2. Informs the configured RememberMeServices of the successful login
	 * 3.Fires an InteractiveAuthenticationSuccessEvent via the configured
	 * ApplicationEventPublisher
	 * 4.Delegates additional behaviour to the AuthenticationSuccessHandler.
	 * 
	 *
	 * Subclasses can override this method to continue the FilterChain after
	 * successful authentication.
	 * @param request
	 * @param response
	 * @param chain
	 * @param authResult the object returned from the attemptAuthentication
	 * method.
	 * @throws IOException
	 * @throws ServletException
	 */
	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);
		}

		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);
	}

	/**
	 * Default behaviour for unsuccessful authentication.
	 * 認證失敗時的預設行為
	 * 
	 * 1.Clears the SecurityContextHolder
	 * 2.Stores the exception in the session (if it exists or
	 *  allowSesssionCreation is set to true)
	 * 3.Informs the configured RememberMeServices of the failed login
	 * 4.Delegates additional behaviour to the AuthenticationFailureHandler.
	 * 
	 */
	protected void unsuccessfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, AuthenticationException failed)
			throws IOException, ServletException {
		SecurityContextHolder.clearContext();

		if (logger.isDebugEnabled()) {
			logger.debug("Authentication request failed: " + failed.toString(), failed);
			logger.debug("Updated SecurityContextHolder to contain null Authentication");
			logger.debug("Delegating to authentication failure handler " + failureHandler);
		}

		rememberMeServices.loginFail(request, response);

		failureHandler.onAuthenticationFailure(request, response, failed);
	}

	protected AuthenticationManager getAuthenticationManager() {
		return authenticationManager;
	}

	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	/**
	 * Sets the URL that determines if authentication is required
	 *
	 * @param filterProcessesUrl
	 */
	public void setFilterProcessesUrl(String filterProcessesUrl) {
		setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(
				filterProcessesUrl));
	}

	public final void setRequiresAuthenticationRequestMatcher(
			RequestMatcher requestMatcher) {
		Assert.notNull(requestMatcher, "requestMatcher cannot be null");
		this.requiresAuthenticationRequestMatcher = requestMatcher;
	}

	public RememberMeServices getRememberMeServices() {
		return rememberMeServices;
	}

	public void setRememberMeServices(RememberMeServices rememberMeServices) {
		Assert.notNull(rememberMeServices, "rememberMeServices cannot be null");
		this.rememberMeServices = rememberMeServices;
	}

	/**
	 * Indicates if the filter chain should be continued prior to delegation to
	 * #successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication)
	 * , which may be useful in certain environment (such as Tapestry applications).
	 * Defaults to false.
	 */
	public void setContinueChainBeforeSuccessfulAuthentication(
			boolean continueChainBeforeSuccessfulAuthentication) {
		this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication;
	}

	public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
		this.eventPublisher = eventPublisher;
	}

	public void setAuthenticationDetailsSource(
			AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
		Assert.notNull(authenticationDetailsSource,
				"AuthenticationDetailsSource required");
		this.authenticationDetailsSource = authenticationDetailsSource;
	}

	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

	protected boolean getAllowSessionCreation() {
		return allowSessionCreation;
	}

	public void setAllowSessionCreation(boolean allowSessionCreation) {
		this.allowSessionCreation = allowSessionCreation;
	}

	/**
	 * The session handling strategy which will be invoked immediately after an
	 * authentication request is successfully processed by the
	 * AuthenticationManager. Used, for example, to handle changing of the
	 * session identifier to prevent session fixation attacks.
	 *
	 * @param sessionStrategy the implementation to use. If not set a null implementation
	 * is used.
	 */
	public void setSessionAuthenticationStrategy(
			SessionAuthenticationStrategy sessionStrategy) {
		this.sessionStrategy = sessionStrategy;
	}

	/**
	 * Sets the strategy used to handle a successful authentication. By default a
	 * SavedRequestAwareAuthenticationSuccessHandler is used.
	 */
	public void setAuthenticationSuccessHandler(
			AuthenticationSuccessHandler successHandler) {
		Assert.notNull(successHandler, "successHandler cannot be null");
		this.successHandler = successHandler;
	}

	public void setAuthenticationFailureHandler(
			AuthenticationFailureHandler failureHandler) {
		Assert.notNull(failureHandler, "failureHandler cannot be null");
		this.failureHandler = failureHandler;
	}

	protected AuthenticationSuccessHandler getSuccessHandler() {
		return successHandler;
	}

	protected AuthenticationFailureHandler getFailureHandler() {
		return failureHandler;
	}
}
           

參考文章

  • Spring Security Web 5.1.2 源碼解析 – 安全相關Filter清單
  • SavedRequestAwareAuthenticationSuccessHandler
  • SimpleUrlAuthenticationFailureHandler
  • WebAuthenticationDetailsSource