1. 程式人生 > >[spring security 那點事兒]配置方式

[spring security 那點事兒]配置方式

這段時間一直開發的B2C的網購平臺已經完成了將近一半的功能,突然覺得自己之前對於許可權管理方面的hold決定將給後面帶來不小的工作量,所以決定現在就加入許可權判斷的功能。很容易聯想到spring security來做這個事情,先看看一個官方文件的翻譯版本:

寫的有些簡略,但是足以能step by step的執行下去。這裡總結一下今天通過名稱空間方式的配置過程吧。

既然要做到自動攔截並進行許可權判斷,很明顯,對於spring security而言,需要有一個監聽器,這個的配置很容易,類似於spring的監聽容器一樣,web.xml中加入配置

然後剩下的事情更簡單了,通常而言,系統中部分url或者程式碼希望被攔截並檢測許可權,如這裡應用到的後臺管理系統,還有一部分是不需要進行攔截的,比如系統的首頁。那麼這個事情是需要你告訴spring security的,在2.0之後引入的namespace的方式將這個過程簡化的非常容易,也就是使用<http/>的方式,這裡暫且略過那段簡單的程式碼,你可以在上面的文件第二章看到那個只有短短几行的配置,卻實現了一個最初的demo。

這裡說說遇到的問題,那就是關於auto-config的問題,auto-config設定為true,spring security預設載入了過濾器並且修正其過濾器的執行順序,避免了由於過濾器執行順序不合適導致的異常。但是這裡一旦配置成預設的true方式,那麼如果你要指定多個驗證資料來源也就是provider,會出現異常:

SecurityConfigurationException: More than one UserDetailsService registered. Please use a specific Id in your configuration

這個異常出現的原因就是因為你使用了auto-config=true,同時又配置了多個UserDetailsService的bean,導致auto-config中預設載入的<remember-me>在裝配UserDetailsService的時候找不到合適的bean,注意這裡的裝配是byType的。比如下面的程式碼就配置了兩個provider,一個是通過資料庫來獲取資料,一個在記憶體中常駐一個預設的超級使用者的配置:

上面的JdbcDaoImpl和InMemoryDaoImpl都是實現了介面UserDetailsService,分別制定了datasource和usermap作為使用者資料的來源。

這個類似於你配置了兩個相同名稱的bean,卻制定了autoWired=byName一樣的道理。解決方法也很簡單,你只需要去掉auto-config=true,然後手動填寫需要的過濾器型別,如果你需要<remember-me/>那麼就手動指定它的userDetailService,如下:

我希望來自資料庫的使用者的資料庫可以被寫入cookie從而實現頁面上的諸如“2周內自動登入”的功能,因為記憶體的那些賬戶是預留的預設最高許可權使用者。當然可能應用場景不同於這樣的簡單,但是解決方案的原理也是相同的。

正如上面所示,我們制定了兩個userDetailService,一個定位於資料庫,一個定位於記憶體,所以同樣的需要配置兩個provider來告訴spring security這兩個的資料提供者:

好了,工作已經完成了,剩下的你可能會想兩方面的問題:

1、頁面的許可權驗證是怎麼執行的?

2、資料庫的資料哪裡來的?我能否自定義表結構來整合自己的專案特殊需求?

第一個問題,許可權驗證如何執行的?看看這裡的http的配置:

很簡單,指明瞭登入頁面,預設登入成功的定位地址,登出後的定位地址,特別注意的是這裡我們必須配置對於圖片和css、js等資源的請求不能被攔截掉,否則頁面會丟失樣式,這裡需要手動的設定對於資原始檔的請求放行,即過濾器不執行攔截,同時由於我們系統使用了dwr來實現非同步互動,所以同樣的這裡也是放行,如果需要進行許可權判斷,則通過其他方式如方法許可權判斷等實現。

 這裡我們自定義了登入頁面,而不是使用spring security那個沒有任何樣式的頁面,那麼在自己的登入頁面的登入表單中,要怎麼去整合spring security呢,很容易,只要將input的名字符合其要求即可:

要注意一下action的url。上面的從session中取出的,是許可權校驗失敗的情況下的錯誤異常資訊,這些資訊由於使用的是namespace的方式,並不能像以前普通bean放下的配置顯示具體的錯誤型別,但是這個也沒什麼關係,由於那個message.properties是一個英文檔案,如果要將詳細的資訊顯示出來,需要執行國際化,但是這裡其實錯誤並無太緊急的需求顯示詳細,所以後續可以通過其他的機制,來顯示一個通用性的資訊即可,或者研究一下在這種namespace的方式下,如何去設定這個地方。

如果既配置http又配置了providerManager會怎樣?http會有效,其中的NamespaceAuthenticationManager方法providerBeanNames引數儲存了namespace方式的配置的預設的provider列表,如果這個引數為空,才回去獲取配置的providerManager配置的provider,但是矛盾的是,如果providerBeanNames為空,卻會丟擲

No authentication providers were found in the application context異常!

所以,這也是行不通的。這裡的應用場景較為初級的使用了spring security,下面要進行的,是針對於本系統的一些特性,尤其是後臺的富客戶端情況下,無法簡單的通過url攔截的方式來實現許可權控制的情況。

第二個問題,處理起來也很簡單,看看官方文件,寫的很清楚了,不羅嗦了