程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> SpringSide 3中的安全框架

SpringSide 3中的安全框架

編輯:關於JAVA

在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開發者來說,常 用的就那麼幾個,如下圖中的被紅圈圈標記出來的:

從上到下,它們實現的功能依次是1、制定必須為https連接;2、從Session中提取用戶的認證信息;3 、退出登錄;4、登錄;5、記住用戶;6、所有的應用必須配置這個Filter。

一般來說,我們寫Web應用只需要熟悉這幾個Filter就可以了,如果不需要https連接,連第一個也不 用熟悉。但是有人肯定會想,這些Filter怎麼和我的數據庫聯系起來呢?不用著急,這些Filter並不直接 處理用戶的認證,也不直接處理用戶的授權,而是把它們交給了認證管理器和決策管理器。如下圖:

對於這兩種管理器,那也是不需要我們寫代碼的,Acegi也提供了現成的類。那麼大家又奇怪了:又是 現成的,那怎麼和我的數據庫關聯起來呢?別著急,其實這兩個管理器自己也不做事,認證管理器把任務 交給了Provider,而決策管理器則把任務交給了Voter,如下圖:

現在我要告訴你們,這裡的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看起來都象角色,不倫不類。

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 UserManageruserManager;
   public UserDetailsloadUserByUsername(StringuserName) throws 

UsernameNotFoundException,DataAccessException{
    Useruser = userManager.getUserByLoginName(userName);
     if (user ==  null )
       throw  new UsernameNotFoundException(userName +  " 不存在 " );
    List < GrantedAuthority > authsList =  new ArrayList < GrantedAuthority 

> ();
     for (Rolerole:user.getRoles()){
       for (Authorityauthority:role.getAuths()){
        authsList.add( new GrantedAuthorityImpl(authority.getName()));
      }
    }
     // 目前在MultiDatabaseExample的User類中沒有

enabled,accountNonExpired,credentialsNonExpired,accountNonLocked等屬性
     // 暫時全部設為true,在需要時才添加這些屬性.
    org.springframework.security.userdetails.Useruserdetail =  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(UserManageruserManager){
     this .userManager = userManager;
  }
}

最後再來說說這個命名的問題,我對Authentication和Authority這兩個單詞比較反感,兩個原因,一 是因為它們太生僻了,二是因為它們長得太像了,明明一個是認證,一個是授權,意思相差很遠,外貌卻 如此相似,確實很煩人。如果讓我來選擇,我喜歡Privilege這個單詞,在我剛使用MySQL的時候就跟它很 熟了,所以在我的項目中,我可能會用Privilege來代替Authority。如果我們只使用User-Role兩級關系 ,使用RoleVoter默認的ROLE_前綴當然沒有關系,如果是像白衣這樣是用三層關系,最好還是把這個前綴 改一改,以免混淆。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved