Spring Security 認(rèn)證簡(jiǎn)介

2018-09-28 19:19 更新

認(rèn)證簡(jiǎn)介

認(rèn)證過程

  1. 用戶使用用戶名和密碼進(jìn)行登錄。
  2. Spring Security 將獲取到的用戶名和密碼封裝成一個(gè)實(shí)現(xiàn)了 Authentication 接口的 UsernamePasswordAuthenticationToken。
  3. 將上述產(chǎn)生的 token 對(duì)象傳遞給 AuthenticationManager 進(jìn)行登錄認(rèn)證。
  4. AuthenticationManager 認(rèn)證成功后將會(huì)返回一個(gè)封裝了用戶權(quán)限等信息的 Authentication 對(duì)象。
  5. 通過調(diào)用 SecurityContextHolder.getContext().setAuthentication(...) 將 AuthenticationManager 返回的 Authentication 對(duì)象賦予給當(dāng)前的 SecurityContext。

上述介紹的就是 Spring Security 的認(rèn)證過程。在認(rèn)證成功后,用戶就可以繼續(xù)操作去訪問其它受保護(hù)的資源了,但是在訪問的時(shí)候?qū)?huì)使用保存在 SecurityContext 中的 Authentication 對(duì)象進(jìn)行相關(guān)的權(quán)限鑒定。

Web 應(yīng)用的認(rèn)證過程

如果用戶直接訪問登錄頁(yè)面,那么認(rèn)證過程跟上節(jié)描述的基本一致,只是在認(rèn)證完成后將跳轉(zhuǎn)到指定的成功頁(yè)面,默認(rèn)是應(yīng)用的根路徑。如果用戶直接訪問一個(gè)受保護(hù)的資源,那么認(rèn)證過程將如下:

  1. 引導(dǎo)用戶進(jìn)行登錄,通常是重定向到一個(gè)基于 form 表單進(jìn)行登錄的頁(yè)面,具體視配置而定。
  2. 用戶輸入用戶名和密碼后請(qǐng)求認(rèn)證,后臺(tái)還是會(huì)像上節(jié)描述的那樣獲取用戶名和密碼封裝成一個(gè) UsernamePasswordAuthenticationToken 對(duì)象,然后把它傳遞給 AuthenticationManager 進(jìn)行認(rèn)證。
  3. 如果認(rèn)證失敗將繼續(xù)執(zhí)行步驟 1,如果認(rèn)證成功則會(huì)保存返回的 Authentication 到 SecurityContext,然后默認(rèn)會(huì)將用戶重定向到之前訪問的頁(yè)面。
  4. 用戶登錄認(rèn)證成功后再次訪問之前受保護(hù)的資源時(shí)就會(huì)對(duì)用戶進(jìn)行權(quán)限鑒定,如不存在對(duì)應(yīng)的訪問權(quán)限,則會(huì)返回 403 錯(cuò)誤碼。

在上述步驟中將有很多不同的類參與,但其中主要的參與者是 ExceptionTranslationFilter。

ExceptionTranslationFilter

ExceptionTranslationFilter 是用來處理來自 AbstractSecurityInterceptor 拋出的 AuthenticationException 和 AccessDeniedException 的。AbstractSecurityInterceptor 是 Spring Security 用于攔截請(qǐng)求進(jìn)行權(quán)限鑒定的,其擁有兩個(gè)具體的子類,攔截方法調(diào)用的 MethodSecurityInterceptor 和攔截 URL 請(qǐng)求的 FilterSecurityInterceptor。當(dāng) ExceptionTranslationFilter 捕獲到的是 AuthenticationException 時(shí)將調(diào)用 AuthenticationEntryPoint 引導(dǎo)用戶進(jìn)行登錄;如果捕獲的是 AccessDeniedException,但是用戶還沒有通過認(rèn)證,則調(diào)用 AuthenticationEntryPoint 引導(dǎo)用戶進(jìn)行登錄認(rèn)證,否則將返回一個(gè)表示不存在對(duì)應(yīng)權(quán)限的 403 錯(cuò)誤碼。

在 request 之間共享 SecurityContext

可能你早就有這么一個(gè)疑問了,既然 SecurityContext 是存放在 ThreadLocal 中的,而且在每次權(quán)限鑒定的時(shí)候都是從 ThreadLocal 中獲取 SecurityContext 中對(duì)應(yīng)的 Authentication 所擁有的權(quán)限,并且不同的 request 是不同的線程,為什么每次都可以從 ThreadLocal 中獲取到當(dāng)前用戶對(duì)應(yīng)的 SecurityContext 呢?在 Web 應(yīng)用中這是通過 SecurityContextPersistentFilter 實(shí)現(xiàn)的,默認(rèn)情況下其會(huì)在每次請(qǐng)求開始的時(shí)候從 session 中獲取 SecurityContext,然后把它設(shè)置給 SecurityContextHolder,在請(qǐng)求結(jié)束后又會(huì)將 SecurityContextHolder 所持有的 SecurityContext 保存在 session 中,并且清除 SecurityContextHolder 所持有的 SecurityContext。這樣當(dāng)我們第一次訪問系統(tǒng)的時(shí)候,SecurityContextHolder 所持有的 SecurityContext 肯定是空的,待我們登錄成功后,SecurityContextHolder 所持有的 SecurityContext 就不是空的了,且包含有認(rèn)證成功的 Authentication 對(duì)象,待請(qǐng)求結(jié)束后我們就會(huì)將 SecurityContext 存在 session 中,等到下次請(qǐng)求的時(shí)候就可以從 session 中獲取到該 SecurityContext 并把它賦予給 SecurityContextHolder 了,由于 SecurityContextHolder 已經(jīng)持有認(rèn)證過的 Authentication 對(duì)象了,所以下次訪問的時(shí)候也就不再需要進(jìn)行登錄認(rèn)證了。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)