一.shiro攔截器基礎類圖
image.png
二.流程介紹
簡述:hiro使用了與Servlet一樣的Filter接口進行擴展钉凌,ShiroFilter是整個程序入口注暗。AdviceFilter 分支责鳍,它提供了 AOP 功能的 Filter,我們也可以集成AdviceFilter下攔截器進行必要操作结序。這些 Filter 就是 Shiro 為我們提供的默認 Filter:
image.png
- Filter接口
public interface Filter {
void init(FilterConfig filterConfig) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
void destroy();
}
- AbstractFilter ,
- 初始化 ServletContext 并封裝 FilterConfig翎卓,實現Filter的init方法中提供供子類實現的 onFilterConfigSet()方法【1】
- NameableFilter
- 每個 Filter 必須有一個名字,可通過 setName 方法設置的偶房,如果不設置就取該 Filter 默認的名字
- OncePerRequestFilter
- 確保每個請求只能被 Filter 過濾一次趁曼。該類第一次實現doFilter()方法 ,其中有供需在子類重寫過濾操作doFilterInternal()【2】方法;
- 可配置的參數:private boolean enabled = true;// 是否開啟過濾功能棕洋,若攔截器配置fasle則跳過繼續(xù)下一個攔截器
AbstractShiroFilter方向分支
- AbstractShiroFilter
實現父對象的 doFilter和 onFilterConfigSet()【1,2】彰阴,獲取 Shiro 代理后的 FilterChain 對象,并進行鏈式處理拍冠,其中 onFilterConfigSet()提供子類實現的init()方法【3】
// 這是 AbstractFilter 提供的在 init 時需要執(zhí)行的方法
protected final void onFilterConfigSet() throws Exception {
// 從 web.xml 中讀取 staticSecurityManagerEnabled 參數(默認為 false)
applyStaticSecurityManagerEnabledConfig();
// 初始化(在子類中實現)
init();
// 確保 SecurityManager 必須存在
ensureSecurityManager();
// 若已開啟 static 標志尿这,則將當前的 SecurityManager 放入 SecurityUtils 中簇抵,以后可以隨時獲取
if (isStaticSecurityManagerEnabled()) {
SecurityUtils.setSecurityManager(getSecurityManager());
}
}
// 這是 OncePerRequestFilter 提供的在 doFilter 時需要執(zhí)行的方法
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException {
Throwable t = null;
try {
// 返回被 Shiro 包裝過的 Request 與 Response 對象
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
// 創(chuàng)建 Shiro 的 Subject 對象
final Subject subject = createSubject(request, response);
// 使用異步的方式執(zhí)行相關操作
subject.execute(new Callable() {
public Object call() throws Exception {
// 更新 Session 的最后訪問時間
updateSessionLastAccessTime(request, response);
// 執(zhí)行 Shiro 的 Filter Chain
executeChain(request, response, chain);
return null;
}
});
}
- ShiroFilter:在 ShiroFilter 中只用做初始化的行為,就是從 WebEnvironment 中分別獲取 WebSecurityManager 與 FilterChainResolver射众,其它的事情都由它的父類去實現了
AdviceFilter方向分支
- AdviceFilter
- 提供了AOP風格的支持碟摆,類似于SpringMVC中的Interceptor。實現了doFilterInternal方法【2】叨橱,方法提供子類實現的preHandle等【4】方法典蜕,并進行鏈式處理。
- preHandler:類似于AOP中的前置增強罗洗;在攔截器鏈執(zhí)行之前執(zhí)行愉舔;如果返回true則繼續(xù)攔截器鏈;否則中斷后續(xù)的攔截器鏈的執(zhí)行直接返回伙菜;進行預處理(如基于表單的身份驗證轩缤、授權)
- postHandle:類似于AOP中的后置返回增強;在攔截器鏈執(zhí)行完成后執(zhí)行贩绕;進行后處理(如記錄執(zhí)行時間之類的)
- afterCompletion:類似于AOP中的后置最終增強火的;即不管有沒有異常都會執(zhí)行;可以進行清理資源(如接觸Subject與線程的綁定之類的)淑倾;
public abstract class AdviceFilter extends OncePerRequestFilter {
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
return true;
}
@SuppressWarnings({"UnusedDeclaration"})
protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
}
public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
}
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain chain) throws Exception {
chain.doFilter(request, response);
}
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
Exception exception = null;
try {
boolean continueChain = preHandle(request, response);
if (log.isTraceEnabled()) {
log.trace("Invoked preHandle method. Continuing chain?: [" + continueChain + "]");
}
if (continueChain) {
executeChain(request, response, chain);
}
postHandle(request, response);
if (log.isTraceEnabled()) {
log.trace("Successfully invoked postHandle method");
}
} catch (Exception e) {
exception = e;
} finally {
cleanup(request, response, exception);
}
}
}
- PathMatchingFilter
- PathMatchingFilter繼承了AdviceFilter馏鹤,提供了url模式過濾的功能,如果需要對指定的請求進行處理娇哆,可以擴展PathMatchingFilter:
- pathsMatch:如果url模式與請求url匹配湃累,那么會執(zhí)行onPreHandle,并把該攔截器配置的參數傳入碍讨。默認什么不處理直接返回true治力。
- onPreHandle:在preHandle中,當pathsMatch匹配一個路徑后垄开,會調用opPreHandler方法并將路徑綁定參數配置傳給mappedValue琴许;然后可以在這個方法中進行一些驗證(如角色授權)税肪,如果驗證失敗可以返回false中斷流程溉躲;默認返回true;也就是說子類可以只實現onPreHandle即可益兄,無須實現preHandle锻梳。如果沒有path與請求路徑匹配,默認是通過的(即preHandle返回true)净捅。