轉自: http://www.blogjava.net/youxia/archive/2008/12/07/244883.html html
在SpringSide 3的官方文檔中,說安全框架使用的是Spring Security 2.0。乍一看,嚇了我一跳,覺得Acegi這麼快就被淘汰了呢。上搜索引擎一搜,發現原來Spring Security 2.0就是Acegi 2.0。懸着的心放下來了。雖然SpringSide 3中關於Acegi的配置文件看起來很不熟悉,可是讀了Acegi 2.0的官方文檔後,一切都釋然了。
先來談一談Acegi的基礎知識,Acegi的架構比較複雜,可是我但願我下面的隻言片語可以把它說清楚。你們都知道,若是要對Web資源進行保護,最好的辦法莫過於Filter,要想對方法調用進行保護,最好的辦法莫過於AOP。Acegi對Web資源的保護,就是靠Filter實現的。以下圖:
通常來講,咱們的Filter都是配置在web.xml中,可是Acegi不同,它在web.xml中配置的只是一個代理,而真正起做用的Filter是做爲Bean配置在Spring中的。web.xml中的代理依次調用這些Bean,就實現了對Web資源的保護,同時這些Filter做爲Bean被Spring管理,因此實現AOP也很簡單,真的是一箭雙鵰啊。
Acegi中提供的Filter很多,有十多個,一個一個學起來比較複雜。可是對於咱們Web開發者來講,經常使用的就那麼幾個,以下圖中的被紅圈圈標記出來的:
從上到下,它們實現的功能依次是一、制定必須爲https鏈接;二、從Session中提取用戶的認證信息;三、退出登陸;四、登陸;五、記住用戶;六、全部的應用必須配置這個Filter。
通常來講,咱們寫Web應用只須要熟悉這幾個Filter就能夠了,若是不須要https鏈接,連第一個也不用熟悉。可是有人確定會想,這些Filter怎麼和個人數據庫聯繫起來呢?不用着急,這些Filter並不直接處理用戶的認證,也不直接處理用戶的受權,而是把它們交給了認證管理器和決策管理器。以下圖:
java
對於這兩種管理器,那也是不須要咱們寫代碼的,Acegi也提供了現成的類。那麼你們又奇怪了:又是現成的,那怎麼和個人數據庫關聯起來呢?彆着急,其實這兩個管理器本身也不作事,認證管理器把任務交給了Provider,而決策管理器則把任務交給了Voter,以下圖:
web
如今我要告訴大家,這裏的Provider和Voter也是不須要咱們寫代碼的。不要崩潰,快到目標了。Acegi提供了多個Provider的實現類,若是咱們想用數據庫來儲存用戶的認證數據,那麼咱們就選擇DaoAuthenticationProvider。對於Voter,咱們通常選擇RoleVoter就夠用了,它會根據咱們配置文件中的設置來決定是否容許某一個用戶訪問制定的Web資源。
而DaoAuthenticationProvider也是不直接操做數據庫的,它把任務委託給了UserDetailService,以下圖:
而咱們要作的,就是實現這個UserDetailService。圖畫得很差,你們不要見笑,可是說了這麼多總算是引出了咱們開發中的關鍵,那就是咱們要實現本身的UserDetailService,它就是鏈接咱們的數據庫和Acegi的橋樑。UserDetailService的要求也很簡單,只須要一個返回org.springframework.security.userdetails.User對象的loadUserByUsername(String userName)方法。所以,怎麼設計數據庫均可以,無論咱們是用一個表仍是兩個表仍是三個表,也無論咱們是用戶-受權,仍是用戶-角色-受權,仍是用戶-用戶組-角色-受權,這些具體的東西Acegi通通不關心,它只關心返回的那個User對象,至於怎麼從數據庫中讀取數據,那就是咱們本身的事了。
反過來再看看上面的過程,咱們發現,即便咱們要作的只是實現本身的UserDetailService類,可是咱們不得不在Spring中配置那一大堆的Bean,包括幾個Filter,幾個Manager,幾個Provider和Voter,而這些配置每每都是重複的無謂的。好在Acegi 2.0也認識到了這個問題,因此,它設計了一個<http>標籤,讓Acegi的配置獲得了簡化。下面是SpringSide 3中的配置的截圖,你們能夠看看:
下圖是官方文章中的傳統Filter設置和<http>元素之間的對應關係:
下面的代碼是SpringSide 3中實現UserDetailService的範例,在SpringSide 3的範例中,白衣使用了三個表User、Role、Authority。可是Acegi不關心你用了幾個表,它只關心UserDetails對象。而決定用戶可否訪問指定Web資源的,是RoleVoter類,無需任何修改它能夠工做得很好,惟一的缺點是它只認ROLE_前綴,因此搞得白衣的Authority看起來都象角色,不三不四。spring
package personal.youxia.service.security; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Required; import org.springframework.dao.DataAccessException; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsService; import org.springframework.security.userdetails.UsernameNotFoundException; import personal.youxia.entity.user.Authority; import personal.youxia.entity.user.Role; import personal.youxia.entity.user.User; import personal.youxia.service.user.UserManager; /** * 實現SpringSecurity的UserDetailsService接口,獲取用戶Detail信息. * * @author calvin */ public class UserDetailServiceImpl implements UserDetailsService { private UserManager userManager; public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException { User user = userManager.getUserByLoginName(userName); if (user == null) throw new UsernameNotFoundException(userName + " 不存在"); List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority>(); for (Role role : user.getRoles()) { for (Authority authority : role.getAuths()) { authsList.add(new GrantedAuthorityImpl(authority.getName())); } } // 目前在MultiDatabaseExample的User類中沒有enabled, accountNonExpired,credentialsNonExpired, accountNonLocked等屬性 // 暫時所有設爲true,在須要時才添加這些屬性. org.springframework.security.userdetails.User userdetail = new org.springframework.security.userdetails.User( user.getLoginName(), user.getPassword(), true, true, true, true, authsList .toArray(new GrantedAuthority[authsList.size()])); return userdetail; } @Required public void setUserManager(UserManager userManager) { this.userManager = userManager; } }