Shiro基礎知識08----攔截器介紹(轉)


1 攔截器介紹

   Shiro使用了與Servlet一樣的Filter接口進行擴展;所以如果對Filter不熟悉可以參考《Servlet3.1規范》 http://www.iteye.com/blogs/subjects/Servlet-3-1了解Filter的工作原理。首先下圖是Shiro攔截器的基礎類圖:

1、NameableFilter
    NameableFilter給Filter起個名字,如果沒有設置默認就是FilterName;還記得之前的如authc嗎?當我們組裝攔截器鏈時會根據這個名字找到相應的攔截器實例;
2、OncePerRequestFilter
    OncePerRequestFilter用於防止多次執行Filter的;也就是說一次請求只會走一次攔截器鏈;另外提供enabled屬性,表示是否開啟該攔截器實例,默認enabled=true表示開啟,如果不想讓某個攔截器工作,可以設置為false即可。
3、ShiroFilter
    ShiroFilter是整個Shiro的入口點,用於攔截需要安全控制的請求進行處理,這個之前已經用過了。
4、AdviceFilter
    AdviceFilter提供了AOP風格的支持,類似於SpringMVC中的Interceptor

  1. boolean preHandle(ServletRequest request, ServletResponse response) throws Exception    
  2. void postHandle(ServletRequest request, ServletResponse response) throws Exception    
  3. void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception;    
    preHandler:類似於AOP中的前置增強;在攔截器鏈執行之前執行;如果返回true則繼續攔截器鏈;否則中斷后續的攔截器鏈的執行直接返回;進行預處理(如基於表單的身份驗證、授權)
    postHandle:類似於AOP中的后置返回增強;在攔截器鏈執行完成后執行;進行后處理(如記錄執行時間之類的);
    afterCompletion:類似於AOP中的后置最終增強;即不管有沒有異常都會執行;可以進行清理資源(如接觸Subject與線程的綁定之類的);

5、PathMatchingFilter
    PathMatchingFilter提供了基於Ant風格的請求路徑匹配功能及攔截器參數解析的功能,如“roles[admin,user]”自動根據“,”分割解析到一個路徑參數配置並綁定到相應的路徑:
  1. boolean pathsMatch(String path, ServletRequest request)    
  2. boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception    
    pathsMatch:該方法用於path與請求路徑進行匹配的方法;如果匹配返回true;
    onPreHandle:在preHandle中,當pathsMatch匹配一個路徑后,會調用opPreHandler方法並將路徑綁定參數配置傳給mappedValue;然后可以在這個方法中進行一些驗證(如角色授權),如果驗證失敗可以返回false中斷流程;默認返回true;也就是說子類可以只實現onPreHandle即可,無須實現preHandle。如果沒有path與請求路徑匹配,默認是通過的(即preHandle返回true)。

6、AccessControlFilter
    AccessControlFilter提供了訪問控制的基礎功能;比如是否允許訪問/當訪問拒絕時如何處理等:

  1. abstract boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;    
  2. boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception;    
  3. abstract boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception;    
    isAccessAllowed:表示是否允許訪問;mappedValue就是[urls]配置中攔截器參數部分,如果允許訪問返回true,否則false;
    onAccessDenied:表示當訪問拒絕時是否已經處理了;如果返回true表示需要繼續處理;如果返回false表示該攔截器實例已經處理了,將直接返回即可。

onPreHandle會自動調用這兩個方法決定是否繼續處理:

  1. boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {    
  2.     return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);    
  3. }   
另外AccessControlFilter還提供了如下方法用於處理如登錄成功后/重定向到上一個請求:
  1. void setLoginUrl(String loginUrl) //身份驗證時使用,默認/login.jsp    
  2. String getLoginUrl()    
  3. Subject getSubject(ServletRequest request, ServletResponse response) //獲取Subject實例    
  4. boolean isLoginRequest(ServletRequest request, ServletResponse response)//當前請求是否是登錄請求    
  5. void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException //將當前請求保存起來並重定向到登錄頁面    
  6. void saveRequest(ServletRequest request) //將請求保存起來,如登錄成功后再重定向回該請求    
  7. void redirectToLogin(ServletRequest request, ServletResponse response) //重定向到登錄頁面     
    比如基於表單的身份驗證就需要使用這些功能。
    到此基本的攔截器就完事了,如果我們想進行訪問訪問的控制就可以繼承AccessControlFilter;如果我們要添加一些通用數據我們可以直接繼承PathMatchingFilter。

2 攔截器鏈

    Shiro對Servlet容器的FilterChain進行了代理,即ShiroFilter在繼續Servlet容器的Filter鏈的執行之前,通過ProxiedFilterChain對Servlet容器的FilterChain進行了代理;即先走Shiro自己的Filter體系,然后才會委托給Servlet容器的FilterChain進行Servlet容器級別的Filter鏈執行;
    Shiro的ProxiedFilterChain執行流程:1、先執行Shiro自己的Filter鏈;2、再執行Servlet容器的Filter鏈(即原始的Filter)。
    而ProxiedFilterChain是通過FilterChainResolver根據配置文件中[urls]部分是否與請求的URL是否匹配解析得到的。

  1. FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);    
    即傳入原始的chain得到一個代理的chain。
    Shiro內部提供了一個路徑匹配的FilterChainResolver實現:PathMatchingFilterChainResolver,其根據[urls]中配置的url模式(默認Ant風格)=攔截器鏈和請求的url是否匹配來解析得到配置的攔截器鏈的;而PathMatchingFilterChainResolver內部通過FilterChainManager維護着攔截器鏈,比如DefaultFilterChainManager實現維護着url模式與攔截器鏈的關系。因此我們可以通過FilterChainManager進行動態動態增加url模式與攔截器鏈的關系。
    DefaultFilterChainManager會默認添加org.apache.shiro.web.filter.mgt.DefaultFilter中聲明的攔截器:
  1. public enum DefaultFilter {    
  2.     anon(AnonymousFilter.class),    
  3.     authc(FormAuthenticationFilter.class),    
  4.     authcBasic(BasicHttpAuthenticationFilter.class),    
  5.     logout(LogoutFilter.class),    
  6.     noSessionCreation(NoSessionCreationFilter.class),    
  7.     perms(PermissionsAuthorizationFilter.class),    
  8.     port(PortFilter.class),    
  9.     rest(HttpMethodPermissionFilter.class),    
  10.     roles(RolesAuthorizationFilter.class),    
  11.     ssl(SslFilter.class),    
  12.     user(UserFilter.class);    
  13. }     
    如果要注冊自定義攔截器,IniSecurityManagerFactory/WebIniSecurityManagerFactory在啟動時會自動掃描ini配置文件中的[filters]/[main]部分並注冊這些攔截器到DefaultFilterChainManager;且創建相應的url模式與其攔截器關系鏈。如果使用Spring后續章節會介紹如果注冊自定義攔截器。
    如果想自定義FilterChainResolver,可以通過實現WebEnvironment接口完成:
  1. public class MyIniWebEnvironment extends IniWebEnvironment {    
  2.     @Override    
  3.     protected FilterChainResolver createFilterChainResolver() {    
  4.         //在此處擴展自己的FilterChainResolver    
  5.         return super.createFilterChainResolver();    
  6.     }    
  7. }     
    FilterChain之間的關系。如果想動態實現url-攔截器的注冊,就可以通過實現此處的FilterChainResolver來完成,比如:
  1. //1、創建FilterChainResolver    
  2. PathMatchingFilterChainResolver filterChainResolver =    
  3.         new PathMatchingFilterChainResolver();    
  4. //2、創建FilterChainManager    
  5. DefaultFilterChainManager filterChainManager = new DefaultFilterChainManager();    
  6. //3、注冊Filter    
  7. for(DefaultFilter filter : DefaultFilter.values()) {    
  8.     filterChainManager.addFilter(    
  9.         filter.name(), (Filter) ClassUtils.newInstance(filter.getFilterClass()));    
  10. }    
  11. //4、注冊URL-Filter的映射關系    
  12. filterChainManager.addToChain("/login.jsp""authc");    
  13. filterChainManager.addToChain("/unauthorized.jsp""anon");    
  14. filterChainManager.addToChain("/**""authc");    
  15. filterChainManager.addToChain("/**""roles""admin");    
  16.     
  17. //5、設置Filter的屬性    
  18. FormAuthenticationFilter authcFilter =    
  19.          (FormAuthenticationFilter)filterChainManager.getFilter("authc");    
  20. authcFilter.setLoginUrl("/login.jsp");    
  21. RolesAuthorizationFilter rolesFilter =    
  22.           (RolesAuthorizationFilter)filterChainManager.getFilter("roles");    
  23. rolesFilter.setUnauthorizedUrl("/unauthorized.jsp");    
  24.     
  25. filterChainResolver.setFilterChainManager(filterChainManager);    
  26. return filterChainResolver;     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM