認證過程如下
一、先判斷請求(請求必須是post請求)地址是否為配置的 login-processing-url 值(默認/j_spring_security_check),如果不是,則放行,進入下一個過濾器,是則進行校驗。
二、驗證用戶密碼信息並返回Authentication類,在驗證過程中如果失敗則捕獲異常進行處理(執行unsuccessfulAuthentication方法調轉到配置中的錯誤鏈接),如果驗證成功,則將調用SessionAuthenticationStrategy中的方法onAuthentication()判斷用戶能否重復登陸,是否二次登陸——根據你的配置文件決定,如果用戶登陸滿足條件則再執行successfulAuthentication(配置中的驗證成功鏈接),如果失敗則還是執行unsuccessfulAuthentication方法
詳細說明:
1、用戶密碼認證過程
AbstractAuthenticationProcessingFilter.doFilter()調用UsernamePasswordAuthenticationFilter中的attemptAuthentication方法,
UsernamePasswordAuthenticationFilter中的attemptAuthentication方法將表單請求的信息(用戶、密碼等信息)賦值給UsernamePasswordAuthenticationToken(authRequest),
然后調用getAuthenticationManager().authenticate(authRequest)對用戶密碼的正確性進行驗證,認證失敗就拋出異常,成功就返回Authentication對象。
AuthenticationManager就是認證管理器,它的方法authenticate執行邏輯如下(默認配置DaoAuthenticationProvider,以DaoAuthenticationProvider為例):
(1)、判斷是否有Authentication 對應的AuthenticationProvider,
有就執行AuthenticationProvider的authenticate方法,
沒有就獲取父類AuthenticationManager,查看父類中是否有Authentication 對應的AuthenticationProvider,
如果也沒有則拋出ProviderNotFoundException異常
(2)執行AuthenticationProvider的authenticate方法
1、根據輸入名,查看緩存中是否已經有有用戶實體對象
如果有,則對密碼重新驗證;
如果沒有,則進行用戶的信息驗證,執行DaoAuthenticationProvider中的retrieveUser方法,獲取一個UserDetails對象
如果UserDetails對象為null或者獲取時出錯就拋出異常UsernameNotFoundException或AuthenticationServiceException異常,
然后一些屬性驗證之后,對用戶密碼進行驗證。
2、給新獲取的UserDetails對象放入緩存中
3、新建一個UsernamePasswordAuthenticationToken一個對象,將authenticated設為true(原來傳入的UsernamePasswordAuthenticationToken對象authenticated為false)並返回
2、SessionAuthenticationStrategy.onAuthentication處理過程(主要處理一個用戶是否可以同時多次登陸)
1、checkAuthenticationAllowed方法
根據maximumSessions和exceptionIfMaximumExceeded的設置判斷
用戶是否多次登陸,
是否超過maximumSessions同時登陸了,
是否限制用戶二次登陸(限制的話則第二次登陸的時候會拋出SessionAuthenticationException異常)還是第二次登陸使第一次登陸無效
2、復制一個新的session,擁有新的sessionID
3、更新SessionRegistry中的ConcurrentMap<Object,Set<String>> principals和Map<String, SessionInformation> sessionIds,這個是在第三個過濾器中ConcurrentSessionFilter需要使用的
2018-03-29總結
AuthenticationManager調用Provider,provider調用userDetaisService來根據username獲取真實的數據庫信息。 而在usernamePasswordAuthenticationFilter中來調用的是AuthenticationManager。。這個流程雖然沒多么復雜,但是花費我不少時間給理解到了。。。