Spring Security 整體架構操作流程
Spring Security 整體架構
前提
開源項目一手文檔基本都在github,標準文檔基本都在官網。
最好的文檔就是官網;
在前些年,Apache下還有個比較流行的權限框架 Shiro,但是隨著Spring Security (以下簡稱 Security)的流行,逐漸邊緣化。其實這類框架整體設計都大差不差,都是基于一系列的過濾器或者其他攔截手段實現增強。
整體架構
Servlet 整體的過濾器模型
這一塊屬于 Servlet 基礎,過濾器算是Servlet核心功能之一,需重點掌握。
Security 過濾器鏈
Security 在 Servlet 過濾器上定義了一個 自己的過濾器(這個過濾器使用了委托者設計模式)
可以看到,Servlet 過濾器鏈上,不僅有 Security 的過濾器還有 Spring Boot 的一些過濾器,但是這里我們重點關注圈起來的那個過濾器(鏈)
再對比官方的這個圖
就更好理解了。
自定義過濾器
我們自定義的過濾器基本都是在 Security 這個過濾器鏈上面的,通過編排不同的順序,實現想要的功能。
在這之前,我們先看看Security默認的過濾器鏈上有哪些過濾器官方列表
這里為了照顧,訪問不了官網的,簡單截個圖。
但不是所有過濾器默認都開啟了的。
上面那個鏈是,Spring 全局的過濾器鏈,里面第四個過濾器委托給了下面那個 Security 的過濾器鏈,在 Security 的過濾器鏈中,可以看到默認有14個過濾器。
其中有幾個重點關注的是:
- SecurityContextPersistenceFilter (即將過時,替代者為 SecurityContextHolderFilter),其功能為,支持默認的基于 Cookie 的登錄形式;
- 對于新接觸認證授權的開發(fā)者,要明白一點,不管什么實現方案,每一次進行鑒權,其本質會進行一次登錄認證,只是方式不同而已LogoutFilter 注銷登錄的過濾器,默認的url為 /logout,要實現自定義退出可以參考
- UsernamePasswordAuthenticationFilter 大部分開發(fā)者,開始接觸 Security 都是模仿這個 過濾器實現的自定義登錄
- AnonymousAuthenticationFilter 在 Security 中,認證沒有通過或者沒有匹配上認證過濾器的請求,最終會被定義為匿名認證,這也是一種認證結果,在權限中也有相關的配置。
其他的過濾器根據自己的需求,調整。
實際開發(fā)解決方案
在實際開發(fā)中,目前通常采用前后端分離的形式;有的前端對Cookie 不太友好;因此,為了統(tǒng)一,大部分開發(fā)者會采用 header 認證方式。
這樣實現起碼會有兩個點需要調整
1.調整默認認證成功的處理方式
默認配置下,認證成功會跳轉到一個指定的頁面;現在大多會把這個跳轉交給前端。
2.改為header 傳遞認證參數后,默認的過濾器就不支持了,需要定義一個 過濾器,解析header,并進行認證;個人推薦將這個認證過濾器放在
AnonymousAuthenticationFilter 的前面,因為前面還有些其他認證過濾器,如果自定義的過濾器太靠前,可能會被其他認證過濾器(比如上面提到的 SecurityContextPersistenceFilter 以及 SecurityContextHolderFilter)給覆蓋掉認證信息,當然這要取決實際的優(yōu)先級,萬一你就想自定義的認證認證過濾器優(yōu)先級低一點呢
可以看到,這兩個認證過濾器不管你是否已經認證,會直接覆蓋掉認證信息。
一個替代cookie認證的filter
提供一個簡單實現,具體業(yè)務邏輯,開發(fā)者自己填充
package authorization.filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collections; public class JwtAuthenticationFilter extends OncePerRequestFilter { private final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("token"); if (!StringUtils.hasText(token)) { filterChain.doFilter(request, response); return; } try { UsernamePasswordAuthenticationToken authenticationToken = UsernamePasswordAuthenticationToken.authenticated("zhangsan", "zs", Collections.emptyList()); SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(authenticationToken); SecurityContextHolder.setContext(context); filterChain.doFilter(request, response); } finally { SecurityContextHolder.clearContext(); } } @Override protected boolean shouldNotFilterErrorDispatch() { return true; } }
其他組件,后續(xù)抽時間再整理整理
到此這篇關于Spring Security 整體架構的文章就介紹到這了,更多相關Spring Security 整體架構內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!