欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot之security?FilterSecurityInterceptor的使用要點記錄

 更新時間:2023年12月11日 10:17:06   作者:一名工程師  
這篇文章主要介紹了springboot之security?FilterSecurityInterceptor的使用要點記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

spring security FilterSecurityInterceptor使用要點

FilterSecurityInterceptor是一個方法級的權限過濾器, 基本位于過濾鏈的最底部

該過濾器用于控制method級別的權限控制. 官方提供了2種默認的方法權限控制寫法

一種是在方法上加注釋實現(xiàn),另一種是在configure配置中通過

@Secured("ROLE_ADMIN") //法1, 方法定義處加注釋, 需先在具體的配置里開啟此類配置
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
	
法2, 在復寫的configure里直接定義
.antMatchers("your match rule").authenticated()
.antMatchers("your match rule").hasRole("ADMIN") //使用時權限會自動加前綴ROLE_ADMIN

具體細節(jié)的代碼就不貼了,官方文檔一模一樣的都有.

上面兩種方法最終都會生成一個FilterSecurityInterceptor實例,放在上面過濾鏈底部. 用于方法級的鑒權.

官方還提到了第三種方法,關于如何把過濾的規(guī)則放到更為靈活的位置,數(shù)據(jù)庫/本地文件/等等.

貼一段官方代碼

public class MyFilterSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

	//此方法用于鑒權過程中獲取當前的請求URL需要哪種權限
    public List<ConfigAttribute> getAttributes(Object object) {
        FilterInvocation fi = (FilterInvocation) object;
            String url = fi.getRequestUrl();
            String httpMethod = fi.getRequest().getMethod();
            List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();

            // Lookup your database (or other source) using this information and populate the
            // list of attributes

            return attributes;
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

具體思路就是通過自定義過濾器的MetadataSource來實現(xiàn)規(guī)則的靈活配置,該部分實例默認使用的是DefaultFilterInvocationSecurityMetadataSource, 可以根據(jù)這里的源碼來編寫自己的MetadataSource.

內(nèi)部使用下面這個結構來維護匹配規(guī)則和對應的權限集

Map<RequestMatcher, Collection<ConfigAttribute>> requestMap

RequestMatcher和ConfigAttribute都是抽象類,需要找個能用的類,通過查閱源碼可以找到RequestMathcer的具體構造實現(xiàn)

RequestMatchers.antMatchers(...)

不過該方法不能直接拿來用,寫了私有

public static List<RequestMatcher> antMatchers(HttpMethod httpMethod,
		String... antPatterns) {
	String method = httpMethod == null ? null : httpMethod.toString();
	List<RequestMatcher> matchers = new ArrayList<>();
	for (String pattern : antPatterns) {
		matchers.add(new AntPathRequestMatcher(pattern, method));
	}
	return matchers;
}

改用new AntPathRequestMatcher(pattern, method)這個就行

ConfigAttribute有一個叫SecurityConfig的實例, 構造時傳入String就可以構造對應的權限實例

不過官方好像沒寫具體怎么注入這個自定義的MetadataSource???

找了半天好像都沒找到能直接注入到默認的Filter的途徑, 沒辦法只能寫一個新的自定義FilterSecurityInterceptor來注入, 通過configure里的addFilter()方法放入過濾鏈

setSecurityMetadataSource()方法寫入自定義的rules源, 還需要注入AccessDecision和Authentication,

前者用于驗證訪問權限, 繼承AccessDecisionManager實現(xiàn)decide方法來編寫自定義的驗證邏輯

decide方法包含 Authentication, 一個Object類型的FilterInvocation實例, 一組ConfigAttribute(要求的權限列表, 從MetaSource的getAttributes()方法里取的, 完整的獲取和校驗上層邏輯都封裝在AbstractSecurityInterceptorbeforeInvocation()方法里)

后者用于驗證登錄授權, 后者使用默認的super.authenticationManager()即可

完成自定義方法級過濾后碰到幾個問題,一個是加入了這個Filter后原先方法1和方法2設置的就都失效了.

這里直接說看源碼打斷點后的結論, 主要是因為自定義的filter加入后, 和原先的默認FilterSecurityInterceptor會有互相排斥的問題, 具體表現(xiàn)為只要這兩個中的其中一個先執(zhí)行invoke()方法, 就會在request里追加一個名為__spring_security_filterSecurityInterceptor_filterApplied的attribute表示FilterSecurityInterceptor這個類型的過濾器已經(jīng)執(zhí)行過了. 當另一個同類的FilterSecurityInterceptor進來時就直接跳過具體的invoke方法直接執(zhí)行下一個過濾器了.

過濾器的位置排序上, addFilter()加的自定義FilterSecurityInterceptor排到了默認的FilterSecurityInterceptor之前,如果要放在默認的后面, 用addFilterAfter()方法, 指定需要放在哪個過濾器后面.

所以對應的解決辦法也很簡單,覆寫自定義過濾器中的invoke方法,把加attribute那段去掉.

我就不處理這個問題了, 其實這個地方算不算一個問題還得單獨考慮的, 包括上面自定義Metadata也是.

有這么幾個其實寫之前就該考慮好的問題.

  • 系統(tǒng)里的方法級權限真的需要通過數(shù)據(jù)庫靈活配置嗎?
  • 系統(tǒng)真的需要讓自定義的filter和默認filter的權限規(guī)則同時生效嗎?

其實spring官方是推薦方法級權限就直接硬編碼的. 因為考慮到放在數(shù)據(jù)庫后, 安全上的風險實在太大了.

僅僅通過修改數(shù)據(jù)庫,即使非admin角色的賬戶也是能獲取所有的操作權限的.

另一點是操作權限定義上的變更(哪些角色該有哪些操作權限?)本身就應該是需要審計的,并且非常低頻的.

硬編碼在排除風險之余,對于實際使用的影響其實也是微乎其微的(無非每次確定要改了,發(fā)一次版)

至于我為何要寫自定義的FilterSecurityInterceptor, 主要是系統(tǒng)的security集成在路由層,那邊不定義方法,法2在configure里硬編碼好像又太繁瑣,所以想在Metadatasource層用文件或者什么靜態(tài)常量的方法硬編碼.

不過最后寫完發(fā)現(xiàn)好像也不便利?并不快樂??? 為了這個目標多寫了好多實現(xiàn)類,并不能輕松愉快地直接注入Metadatasource.

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

最新評論