二、Spring Security預設認證流程及其優缺點
1、Spring Security預設認證流程總結
四、Spring Boot整合Spring Security之認證流程詳細介紹了認證流程,其核心流程如下
- SecurityContextPersistenceFilter:chain.doFilter()前從安全上下文倉庫中獲取安全上下文,未登入狀態時獲取未認證的安全上下文;chain.doFilter()後從安全上下文持有者中獲取安全上下文並更新到安全上下文倉庫中
- LogoutFilter:如果是登出請求,清除安全上下文認證資訊並重定向到登入頁面,否則不處理
- UsernamePasswordAuthenticationFilter:如果是登入請求,校驗請求引數中的使用者名稱密碼,校驗成功後生成新的已認證的安全上下文並儲存到安全上下文倉庫中後重定向到目標URL,否則不處理
- DefaultLoginPageGeneratingFilter:如果是登入頁面請求,返回預設登入頁面,否則不處理
- DefaultLogoutPageGeneratingFilter:如果是登出頁面請求,返回預設登出頁面,否則不處理
2、優缺點
- 提供了完整的安全的認證流程
- 預設基於session實現非前後分離專案的認證流程,該流程已經慢慢退出歷史舞臺
- 未提供前後分離認證流程
三、前後分離專案認證思路
1、前後分離專案認證流程(基於預設流程最佳化)
- 前端輸入使用者名稱密碼提交到後端
- 後端獲取到使用者名稱密碼並校驗,校驗成功後生成token(類似於sessionId)返回給前端,生成已認證的安全上下文(類似於session)儲存到安全上下文倉庫中
- 前端獲取到token,後續每次請求的請求頭中都攜帶該token(類似於cookie)
- 後端獲取請求頭中的token,透過token獲取安全上下文,並設定到安全上下文持有者中
- 前端提交退出請求時,後端獲取請求頭中的token,並透過token刪除安全上下文倉庫中安全上下文
2、前後分離專案認證流程關鍵元件對應的預設實現
從前後分離專案認證流程可以看出有四個關鍵元件
- 每次請求時透過請求頭中token從安全上下文倉庫中獲取安全上下文的過濾器(預設SecurityContextPersistenceFilter)
- 登出時透過請求頭中的token從安全上下文倉庫中清除安全上下文的過濾器(預設LogoutFilter)
- 登入時驗證使用者名稱密碼並生成token和安全上下文,將安全上下文新增到安全上下文倉庫中的過濾器(預設UsernamePasswordAuthenticationFilter)
- 安全上下文倉庫(預設HttpSessionSecurityContextRepository)
3、預設實現的侷限性
- UsernamePasswordAuthenticationFilter從form表單中獲取請求引數,不符合RESTFUL開發規範
- 認證的關鍵元件AuthenticationManager未注入到Spring容器中,導致自定義認證過濾器無法直接從Spring容器中獲取
- UsernamePasswordAuthenticationFilter只實現了認證部分,認證成功後生成的安全上下文並新增安全上下文倉庫中過程無法控制,只能使用預設的HttpSession或RequestAttributes方式,無法自定義
4、整改思路
- 自定義SecurityContextRepositoryImpl實現安全上下文倉庫SecurityContextRepository,實現基於分散式快取的安全上下文倉庫
- 自定義RestfulUsernamePasswordAuthenticationFilter繼承AbstractAuthenticationProcessingFilter,實現符合RESTFUL開發規範的登入方式
- 自定義UserDetailsImpl實現UserDetails介面,方便新增自定義屬性
- 自定義UserDetailsServiceImpl實現UserDetailsService介面,實現基於資料庫的認證方式,並生成token設定到UserDetails中
5、整改後的認證流程
- 前端輸入使用者名稱密碼提交到後端
- 後端AbstractAuthenticationProcessingFilter呼叫子類RestfulUsernamePasswordAuthenticationFilter的attemptAuthentication方法獲取認證資訊
- RestfulUsernamePasswordAuthenticationFilter獲取請求中的使用者名稱密碼,並呼叫UserDetailsService的loadUserByUsername獲取使用者資訊
- UserDetailsServiceImpl透過使用者名稱查詢使用者,將使用者資訊設定到建立的UserDetailsImpl物件中,生成token設定到UserDetailsImpl物件中
- AbstractAuthenticationProcessingFilter呼叫SecurityContextRepositoryImpl儲存安全上下文
- SecurityContextRepositoryImpl獲取安全上下文及其認證資訊中的token,將token和安全上下文新增到分散式快取中
- 將token返回到前端
- 前端獲取token,每次請求時都在請求頭中攜帶該token
- SecurityContextPersistenceFilter/SecurityContextHolderFilter呼叫SecurityContextRepositoryImpl的loadContext獲取安全上下文
- SecurityContextRepositoryImpl獲取請求頭中token,使用token從分散式快取中獲取安全上下文並返回
- 前端提交登出請求
- LogoutFilter呼叫SecurityContextRepositoryImpl的saveContext,其中引數安全上下文為空值安全上下文
- SecurityContextRepositoryImpl判斷出空值安全上下文,獲取請求頭中的token,使用token刪除分散式快取中獲取安全上下文
四、總結
1、設計前後分離專案認證流程原則
- 儘可能貼合原生Spring Security處理流程,儘量使用Spring Security提供的元件
- 介面設計符合RESTFUL介面規範
- 使用分散式快取儲存登入憑證,更適合分散式專案
2、其他說明
- 這裡說的前後分離專案認證流程最佳方案,是個人認為的最佳方案,並非行業公認的最佳方案,一千個讀者就有一千個哈姆雷特,歡迎在評論區或者私信討論你心中的最佳方案
- 下文程式碼實現該方案,敬請期待