SpringBoot+Shiro學習(七):Filter過濾器管理
先從我們寫的一個自定義Filter來看:
public class RoleOrFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = getSubject(request,response);
String[] roles = (String[])mappedValue;
if(roles == null || roles.length ==0){
return true;
}
for(String role:roles){
if(subject.hasRole(role)){
return true;
}
}
return false;
}
}
我們寫的自定義RoleOrFilter表示有多個角色要求時,只需要滿足一個即可通過。
我們順著RoleOrFilter的實現,瞭解他的父類
NameableFilter
NameableFilter給Filter起個名字,如果沒有設定預設就是FilterName;還記得之前的如authc嗎?當我們組裝攔截器鏈時會根據這個名字找到相應的攔截器例項;
OncePerRequestFilter
OncePerRequestFilter用於防止多次執行Filter的;也就是說一次請求只會走一次攔截器鏈;另外提供enabled屬性,表示是否開啟該攔截器例項,預設enabled=true表示開啟,如果不想讓某個攔截器工作,可以設定為false即可。
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與執行緒的繫結之類的);
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)。
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會自動呼叫這兩個方法決定是否繼續處理:
boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}
另外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。
AuthorizationFilter
AuthorizationFilter實現了AccessControlFilter的onAccessDenied方法
//訪問拒絕才會進來此方法
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
Subject subject = getSubject(request, response);
if (subject.getPrincipal() == null) {
// 如果未登入,儲存當前頁面,重定向到登入頁面
saveRequestAndRedirectToLogin(request, response);
} else {
//匿名訪問地址
String unauthorizedUrl = getUnauthorizedUrl();
if (StringUtils.hasText(unauthorizedUrl)) {
//如果匿名訪問地址存在,則跳轉去匿名訪問地址
WebUtils.issueRedirect(request, response, unauthorizedUrl);
} else {
//不存在則返回404
WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
return false;
}
ShiroFilterFactoryBean
當我們寫好了自定義Filter後,如何在Shiro中使用它呢?在config類中注入ShiroFilter的bean
/**
* ShiroFilter主要配置
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter (SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//自定義攔截器
Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
filtersMap.put("roleOrFilter", roleOrFilter());
shiroFilterFactoryBean.setFilters(filtersMap);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//注意過濾器配置順序 不能顛倒
//配置退出 過濾器,其中的具體的退出程式碼Shiro已經替我們實現了,登出後跳轉配置的loginUrl
filterChainDefinitionMap.put("/logout", "logout");
// 配置不會被攔截的連結 順序判斷
//filterChainDefinitionMap.put("/hello", "anon");
filterChainDefinitionMap.put("/ajaxLogin", "anon");
filterChainDefinitionMap.put("/testRole", "anon");
filterChainDefinitionMap.put("/**", "roleOrFilter[admin,admin1]");
//自動跳去登入的地址
shiroFilterFactoryBean.setLoginUrl("/login");
//上面提到的匿名地址
//shiroFilterFactoryBean.setUnauthorizedUrl();
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
這樣我們在訪問對應的請求時,就會先呼叫shiro的filter。
預設攔截器名 | 攔截器類 | 說明(括號裡的表示預設值) |
---|---|---|
身份驗證相關的 | ||
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | 基於表單的攔截器;如“/**=authc”,如果沒有登入會跳到相應的登入頁面登入;主要屬性:usernameParam:表單提交的使用者名稱引數名( username); passwordParam:表單提交的密碼引數名(password); rememberMeParam:表單提交的密碼引數名(rememberMe); loginUrl:登入頁面地址(/login.jsp);successUrl:登入成功後的預設重定向地址; failureKeyAttribute:登入失敗後錯誤資訊儲存key(shiroLoginFailure); |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | Basic HTTP身份驗證攔截器,主要屬性: applicationName:彈出登入框顯示的資訊(application); |
logout | org.apache.shiro.web.filter.authc.LogoutFilter | 退出攔截器,主要屬性:redirectUrl:退出成功後重定向的地址(/) |
user | org.apache.shiro.web.filter.authc.UserFilter | 使用者攔截器,使用者已經身份驗證/記住我登入的都可; |
anon | org.apache.shiro.web.filter.authc.AnonymousFilter | 匿名攔截器,即不需要登入即可訪問;一般用於靜態資源過濾;示例“/static/**=anon” |
授權相關的 | ||
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | 角色授權攔截器,驗證使用者是否擁有所有角色;主要屬性: loginUrl:登入頁面地址(/login.jsp);unauthorizedUrl:未授權後重定向的地址;示例“/admin/**=roles[admin]” |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | 許可權授權攔截器,驗證使用者是否擁有所有許可權;屬性和roles一樣;示例“/user/**=perms["user:create"]” |
port | org.apache.shiro.web.filter.authz.PortFilter | 埠攔截器,主要屬性:port(80):可以通過的埠;示例“/test= port[80]”,如果使用者訪問該頁面是非80,將自動將請求埠改為80並重定向到該80埠,其他路徑/引數等都一樣 |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | rest風格攔截器,自動根據請求方法構建許可權字串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)構建許可權字串;示例“/users=rest[user]”,會自動拼出“user:read,user:create,user:update,user:delete”許可權字串進行許可權匹配(所有都得匹配,isPermittedAll); |
ssl | org.apache.shiro.web.filter.authz.SslFilter | SSL攔截器,只有請求協議是https才能通過;否則自動跳轉會https埠(443);其他和port攔截器一樣; |
自定義filter異常
此外,我在查詢資料的時候,看到一個問題Shiro 自定義 filter 匹配異常,問題主要說在使用自定義filter定義的時候,使用@Bean模式注入自定義filter之後,會導致自定義filter的呼叫在shiroFilter的前面,具體解決方案可以點開原文看。
我在我本地測試後發現沒有問題,可能是新版本已經修復了這個bug。當前版本1.3.2
相關文章
- Filter過濾器Filter過濾器
- PHP 過濾器(Filter)PHP過濾器Filter
- JavaWeb 中 Filter過濾器JavaWebFilter過濾器
- Filter過濾器的使用Filter過濾器
- filter過濾Filter
- 布隆過濾器(Bloom Filter)過濾器OOMFilter
- 布隆過濾器 Bloom Filter過濾器OOMFilter
- Bloom Filter 布隆過濾器OOMFilter過濾器
- 攔截器(Interceptor)與過濾器(Filter)過濾器Filter
- HBase Filter 過濾器之 ValueFilter 詳解Filter過濾器
- 如何在vue中使用過濾器filterVue過濾器Filter
- Vue定義全域性過濾器filterVue過濾器Filter
- 布隆過濾器(Bloom Filter)詳解過濾器OOMFilter
- Filter(過濾器)與Listener(監聽器)詳解Filter過濾器
- 過濾器 Filter 與 攔截器 Interceptor 的區別過濾器Filter
- JavaWeb - 【Filter】敏感詞過濾JavaWebFilter
- Elasticsearch——filter過濾查詢ElasticsearchFilter
- PCL學習記錄-1 Filter-1 PassThrough filter(直通濾波器)功能及用法解析Filter
- 基礎設計模式-03 從過濾器(Filter)校驗鏈學習職責鏈模式設計模式過濾器Filter
- SpringCloud學習系列之七 ----- Zuul路由閘道器的過濾器和異常處理SpringGCCloudZuul路由過濾器
- Laravel 模型過濾(Filter)設計Laravel模型Filter
- 微信小程式 使用filter過濾器幾種方式微信小程式Filter過濾器
- Solon 的過濾器 Filter 和兩種攔截器 Handler、 Interceptor過濾器Filter
- java中listFiles(Filefilter filter)檔案過濾器的實現過程JavaFilter過濾器
- 使用Filter介面編寫過濾器解決post亂碼Filter過濾器
- 從零手寫實現 tomcat-11-filter 過濾器TomcatFilter過濾器
- Django(69)最好用的過濾器外掛Django-filterDjango過濾器Filter
- 雜湊表擴充套件—布隆過濾器(Bloom Filter)套件過濾器OOMFilter
- LevelDB 學習筆記1:布隆過濾器筆記過濾器
- Vue學習(一)過濾器以及padStart和padEndVue過濾器
- 【GreatSQL最佳化器-05】條件過濾condition_fanout_filterSQLFilter
- Filter-Policy過濾策略&Route-policyFilter
- filter在JavaScript中過濾陣列元素FilterJavaScript陣列
- SpringBoot+Shiro學習(四):Realm授權Spring Boot
- 042.CI4框架CodeIgniter,控制器過濾器Filter配合Services的使用框架過濾器Filter
- Fabric 1.0原始碼分析(11)consenter(共識外掛) #filter(過濾器)原始碼Filter過濾器
- java8 多條件的filter過濾JavaFilter
- 過濾器過濾器