1. 程式人生 > >spring security控制權限的幾種方法

spring security控制權限的幾種方法

使用Spring Security3的四種方法概述

    那麼在Spring Security3的使用中,有4種方法:

    一種是全部利用配置檔案,將使用者、許可權、資源(url)硬編碼在xml檔案中,已經實現過,並經過驗證;

    二種是使用者和許可權用資料庫儲存,而資源(url)和許可權的對應採用硬編碼配置,目前這種方式已經實現,並經過驗證。

    三種是細分角色和許可權,並將使用者、角色、許可權和資源均採用資料庫儲存,並且自定義過濾器,代替原有的FilterSecurityInterceptor過濾器,
    並分別實現AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,並在配置檔案中進行相應配置。
    目前這種方式已經實現,並經過驗證。

    四是修改spring security的原始碼,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService兩個類。
    前者是將配置檔案或資料庫中儲存的資源(url)提取出來加工成為url和許可權列表的Map供Security使用,後者提取使用者名稱和許可權組成一個完整的(UserDetails)User物件,該物件可以提供使用者的詳細資訊供AuthentationManager進行認證與授權使用。
    該方法理論上可行,但是比較暴力,也沒有時間實現,未驗證,以後再研究。

    說明一下,我目前調通的環境為: java1.6 + struts2.1.6 + spring3.0.1 + hibernate3.3.1 + spring security3.0.2 + oracle9i + weblogic10.3,
    順便提一下,目前(2011-4-2)serutity的最新版本為3.1,比較穩定的版本為3.0.5和2.0.6。

    當然在進行spring security3的下面4種方法介紹之前,先假定SSH2的環境已經配置完畢,進入正常開發的過程,並且已經匯入
    spring security3.0.2的5個jar包,分別為:
    spring-security-acl-3.0.2.RELEASE.jar
    spring-security-config-3.0.2.RELEASE.jar
    spring-security-core-3.0.2.RELEASE.jar
    spring-security-taglibs-3.0.2.RELEASE.jar
    spring-security-web-3.0.2.RELEASE.jar
    當然還有其他相關的jar包,在此不再贅述。


第一種方法

    第一種方法比較簡單,可參考Spring Security自帶的例子spring-security-samples-tutorial-3.0.2.RELEASE。
這裡給出下載網址:http://www.springsource.com/download/community?sid=1087087,不過在下載之前必須填寫相應的使用者資訊,才允許下載。各種版本號的均可以下載。

    在spring-security-samples-tutorial-3.0.2.RELEASE的例子裡,硬編碼的配置請參見applicationContext-security.xml檔案中的內容。
    裡面配置了使用者名稱、經過MD5加密後的密碼密文、相關的許可權,以及與權相對應的訪問資源(URL)。還有對於Session超時時的處理。
    特別是因為版本號為3.0.2,因此還增加了對錶達式的配置演示,具體內容請參見該例子。

    當然你最好執行起該例子來,感受一下,你可以直接將下載下來的解壓縮後的資料夾中找到spring-security-samples-tutorial-3.0.2.RELEASE.war檔案,然後拷貝到Tomcat的安裝目錄下的\webapps資料夾下,然後執行Tomcat的伺服器,伺服器在啟動過程中,會自動解開該war檔案,在IE內輸入http://localhost:8080/webapps/spring-security-samples-tutorial-3.0.2.RELEASE 就可以執行該系統了。在此不再贅述。

第二種方法

    第二種方法的程式碼如下:

    使用到的兩個表,使用者表和許可權表的SQL語句。將使用者和許可權以資料庫進行儲存。

create table USERS(
  USERNAME   VARCHAR2(50) not null,
  PASSWORD   VARCHAR2(50) not null,
  ENABLED    NUMBER(1) not null,
  USERNAMECN VARCHAR2(50),
  primary key( username )
)

create table AUTHORITIES(
  USERNAME  VARCHAR2(50) not null,
  AUTHORITY VARCHAR2(50) not null
)

-- 外來鍵使使用者和許可權相聯。
Create/Recreate primary, unique and foreign key constraints 
alter table AUTHORITIES
add constraint FK_AUTHORITIES_USERS foreign key (USERNAME)
references USERS (USERNAME);


可插入幾條資料做為試驗,首先插入使用者:
insert into users (USERNAME, PASSWORD, ENABLED, USERNAMECN, ROWID)
values ('lxb', 'c7d3f4c857bc8c145d6e5d40c1bf23d9', 1, '登入使用者', 'AAAHmhAALAAAAAOAAA');

insert into users (USERNAME, PASSWORD, ENABLED, USERNAMECN, ROWID)
values ('admin', 'ceb4f32325eda6142bd65215f4c0f371', 1, '系統管理員', 'AAAHmhAALAAAAAPAAA');

insert into users (USERNAME, PASSWORD, ENABLED, USERNAMECN, ROWID)
values ('user', '47a733d60998c719cf3526ae7d106d13', 1, '普通使用者', 'AAAHmhAALAAAAAPAAB');

再插入角色:
insert into authorities (USERNAME, AUTHORITY, ROWID)
values ('admin', 'ROLE_PLATFORMADMIN', 'AAAHmjAALAAAAAgAAA');

insert into authorities (USERNAME, AUTHORITY, ROWID)
values ('admin', 'ROLE_SYSADMIN', 'AAAHmjAALAAAAAgAAB');

insert into authorities (USERNAME, AUTHORITY, ROWID)
values ('lxb', 'ROLE_LOGIN', 'AAAHmjAALAAAAAeAAA');

insert into authorities (USERNAME, AUTHORITY, ROWID)
values ('lxb', 'ROLE_LOGINTOWELCOME', 'AAAHmjAALAAAAAeAAB');

insert into authorities (USERNAME, AUTHORITY, ROWID)
values ('user', 'ROLE_USER', 'AAAHmjAALAAAAAgAAC');

第二種方法之密碼加密

    可能要有人要問,使用者表裡面的密碼是如何取得的呢?這個密碼是通過MD5進行加密過的,並且以使用者名稱做為了鹽值,最後就成為32位數字這個樣子,這個你可以參見下面applicationContext-Security.xml中的password-encoder和salt-source的配置就會明白。
    那麼在spring security3中是如何加密的呢?當我們設定了pawwrod-encoder和salt-source之後,Spring Security3會根據配置,採用相匹配的加密演算法(比如設定了MD5加密演算法)再加上salt-source進行加密,形成32位數字的密文。
    比如使用者名稱為yew,密碼為yew1234,鹽值為使用者名稱yew。那麼最後加密的明文為“yew1234{yew}”,密文就為“8fe2657d1599dba8e78a7a0bda8651bb”。

    我們在試驗過程中,通常喜歡先將幾個常用的使用者及密碼插入資料庫進行試驗,這種情況下如何得到該使用者的密碼密文呢?
    不妨試試我這個辦法,假設,使用者名稱為user,密碼明文為user369,而且在配置檔案裡面設定了以MD5作為加密演算法,並以使用者名稱做為鹽值。
    那麼你可以首先將各個資訊組合成待加密的密碼明文, 應是 密碼明文 + { + 鹽值 + }, 那麼很明顯,上述user的密碼明文應當是:

    user369{user}

    哈哈,屢試不爽啊。這個方法要謹慎使用,一般人我不告訴他。


第二種方法之相關配置

    將許可權及資源(URL或Action)的關係配置在xml檔案中,並且配置與Spring Security3相關的其他配置:

    1、applicationContext-Security.xml程式碼

<b:beans xmlns="http://www.springframework.org/schema/security"
 xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.0.xsd">

 <http auto-config="true" access-denied-page="/accessDenied.jsp">
  <!-- 不要過濾圖片等靜態資源,其中**代表可以跨越目錄,*不可以跨越目錄。 -->
  <intercept-url pattern="/**/*.jpg" filters="none" />
  <intercept-url pattern="/**/*.png" filters="none" />
  <intercept-url pattern="/**/*.gif" filters="none" />
  <intercept-url pattern="/**/*.css" filters="none" />
  <intercept-url pattern="/**/*.js" filters="none" />
  <!-- 登入頁面和忘記密碼頁面不過濾 -->
  <intercept-url pattern="/login.jsp" filters="none" />
  <intercept-url pattern="/jsp/forgotpassword.jsp"   filters="none" /> 

   <!-- 下面是對Action配置。表示具有訪問/unitsManager資源的使用者必須具有ROLE_PLATFORMADMIN的許可權。
                      當用戶登入時,SS3將使用者的所有許可權從資料庫中提取出來,形成列表。 當用戶訪問該資源時,SS3將
                      登入使用者的許可權列表提出來跟下面配置的許可權進行比對,若有,則允許訪問,若沒有,則給出AccessDeniedException。-->
  <intercept-url pattern="/unitsManager"   access="ROLE_PLATFORMADMIN" />
  <intercept-url pattern="/usersManager"  access="ROLE_PLATFORMADMIN" />

  <intercept-url pattern="/horizontalQuery"  access="ROLE_PLATFORMADMIN" />
   
  <intercept-url pattern="/verticalQuery"    access="ROLE_PLATFORMADMIN" />
  
  <form-login login-page="/login.jsp"  authentication-failure-url="/login.jsp?error=true"   default-target-url="/index.jsp" />

  <!-- "記住我"功能,採用持久化策略(將使用者的登入資訊存放在資料庫表中) -->
  <remember-me data-source-ref="dataSource" />
  
  <!-- 檢測失效的sessionId,超時時定位到另外一個URL -->
  <session-management invalid-session-url="/sessionTimeout.jsp" />
  
 </http>

 <!-- 注意能夠為authentication-manager 設定alias別名  -->
 <authentication-manager alias="authenticationManager">
      <authentication-provider user-service-ref="userDetailsManager">
           <password-encoder ref="passwordEncoder">
                <!-- 使用者名稱做為鹽值 -->
                <salt-source user-property="username" />
           </password-encoder>
      </authentication-provider>
 </authentication-manager>

</b:beans>

2、applicationContext.service.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:util="http://www.springframework.org/schema/util"
 xmlns:jee="http://www.springframework.org/schema/jee" 
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx" 
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
   http://www.springframework.org/schema/jee
   http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/util 
   http://www.springframework.org/schema/util/spring-util-3.0.xsd">
 
 <!-- 定義上下文返回的訊息的國際化。 -->
 <bean id="messageSource"
  class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
  <property name="basename"
   value="classpath:org/springframework/security/messages_zh_CN"/>
 </bean>

 <!--   事件監聽:實現了 ApplicationListener監聽介面,包括AuthenticationCredentialsNotFoundEvent 事件,
  AuthorizationFailureEvent事件,AuthorizedEvent事件, PublicInvocationEvent事件 -->
 <bean  class="org.springframework.security.authentication.event.LoggerListener" />

 <!-- 使用者的密碼加密或解密 -->
 <bean id="passwordEncoder"
  class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />


 <!-- 使用者詳細資訊管理 : 資料來源、使用者快取、啟用使用者組功能。  -->
 <bean id="userDetailsManager"
  class="org.springframework.security.provisioning.JdbcUserDetailsManager">
  <property name="dataSource" ref="dataSource" />
  <property name="userCache" ref="userCache" />
 </bean> 
 
 <bean id="userCache"
  class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
  <property name="cache" ref="userEhCache" />
 </bean> 
 
 
 <bean id="userEhCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  <property name="cacheName" value="userCache" />
  <property name="cacheManager" ref="cacheManager" />
 </bean>
 
 <!-- 快取使用者管理 -->
 <bean id="cacheManager"
  class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
  

 <!-- spring security自帶的與許可權有關的資料讀寫Jdbc模板 -->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource" />
 </bean>

</beans>

3、web.xml:
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">


 <!-- 設定log4j存放Log檔案位置(通過spring統一進行管理) -->
 <context-param>
  <param-name>webAppRootKey</param-name>
  <param-value>log.root</param-value>
 </context-param>

 <!-- 載入log4j的配置檔案 -->
 <context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>classpath:/log4j.properties</param-value>
 </context-param>

 <!--Spring預設重新整理Log4j配置檔案的間隔,單位為millisecond-->
 <context-param>
  <param-name>log4jRefreshInterval</param-name>
  <param-value>60000</param-value>
 </context-param>

 <!--Spring用於log4j初始化的監聽器-->
 <listener>
  <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
 </listener>

 <!--
  載入Spring XML配置檔案,Spring安全配置及各類資原始檔,暫不加
  /WEB-INF/applicationContext-security.xml,
 -->
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
           /WEB-INF/applicationContext*.xml,
           classpath*:applicationContext.xml
        </param-value>
 </context-param>

 <!--spring監聽器的配置,用於在啟動Web容器時,自動裝配ApplicationContext的配置資訊-->
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <!-- 使用Spring中的過濾器解決在請求和應答中的中文亂碼問題 -->
 <filter>
  <filter-name>characterEncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>gbk</param-value>
  </init-param>
  <init-param>
   <!--強制轉換編碼(request和response均適用) -->
   <param-name>ForceEncoding</param-name>
   <param-value>true</param-value>
  </init-param>
 </filter>

 <filter-mapping>
  <filter-name>characterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 
 <!-- Spring Secutiry3.0.2的過濾器鏈配置  -->
 <filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 
    <!-- 配置Struts2的FilterDispathcer的Filter -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
         org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
        </filter-class>        
    </filter>

 <!-- struts2用以處理使用者Web請求的路徑模式-->
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
   
 
 <!-- 避免亂碼問題 -->
 <filter>
        <filter-name>struts-cleanup</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.ActionContextCleanUp
        </filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>struts-cleanup</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- Spring重新整理Interceptor防止記憶體洩漏  -->
    <listener>
     <listener-class>
     org.springframework.web.util.IntrospectorCleanupListener
     </listener-class>
    </listener>
 

 <!-- 設定session 超時時間為20分鐘  -->
 <session-config>
  <session-timeout>20</session-timeout>
 </session-config>

 <!--系統歡迎頁面-->
 <welcome-file-list>
  <welcome-file>login.jsp</welcome-file>
 </welcome-file-list>

</web-app>
 令人欣喜的是,整個Security配置過程中,除了建立資料庫和編寫配置檔案之外,不需要編寫任何的程式碼。怎麼樣? 有點意思吧!

第二種方法中遇見的問題

    當然,首次使用Spring serutiry,在整合的過程中,我還是遇見了不少問題,當然有些問題比如找不到類呀,包呀,和框架的整合呀等問題不作為談論的重點。主要還是探討Spring Security的配置和注意事項的問題。

    我在其中碰到的對我印象最深的問題是,當完全配置好之後,重啟Web伺服器,卻發現Spring Security不能攔截任何的URL了,這使我感到驚詫,因為在去年時,我已經將該框架搭建完成,在當時正是使用的該種方法,並且在試驗是否能夠攔截jsp檔案時進行了確認是沒有問題的。

    接下來我又整理了一下applicationContext-security.xml的檔案才發現, 除了不需要進行檢測的圖片及登入頁面之外,沒有對任何的資源和許可權之間的對應關係進行配置,參見下面的程式碼:

<http auto-config="true" access-denied-page="/accessDenied.jsp">
  <!-- 不要過濾圖片等靜態資源,其中**代表可以跨越目錄,*不可以跨越目錄。 -->
  <intercept-url pattern="/**/*.jpg" filters="none" />
  <intercept-url pattern="/**/*.png" filters="none" />
  <intercept-url pattern="/**/*.gif" filters="none" />
  <intercept-url pattern="/**/*.css" filters="none" />
  <intercept-url pattern="/**/*.js" filters="none" />
  <!-- 登入頁面和忘記密碼頁面不過濾 -->
  <intercept-url pattern="/login.jsp" filters="none" />
  <intercept-url pattern="/jsp/forgotpassword.jsp" filters="none" /> 

             <!-- 下面是對Struts2的Action請求時的配置。注意在前面加/,否則不會被SS3進行攔截驗證。
                  表示具有訪問/unitsManager資源的使用者必須具有ROLE_PLATFORMADMIN的許可權。
                  當用戶登入時,SS3將使用者的所有許可權從資料庫中提取出來,形成列表。 當用戶訪問該資源時,
                  SS3將登入使用者的許可權列表提出來跟下面配置的許可權進行比對,若有,則允許訪問,若沒有,
                  則給出AccessDeniedException。 
  <intercept-url pattern="/unitsManager"  access="ROLE_PLATFORMADMIN" />
  <intercept-url pattern="/usersManager"  access="ROLE_PLATFORMADMIN" />
  <intercept-url pattern="/horizontalQuery" access="ROLE_PLATFORMADMIN" /> 
  <intercept-url pattern="/verticalQuery"  access="ROLE_PLATFORMADMIN" />   -->
  
  <form-login login-page="/login.jsp" 
   authentication-failure-url="/login.jsp?error=true"
   default-target-url="/index.jsp" />

  <!-- "記住我"功能,採用持久化策略(將使用者的登入資訊存放在資料庫表中) -->
  <remember-me data-source-ref="dataSource" />
  
  <!-- 檢測失效的sessionId,超時時定位到另外一個URL -->
  <session-management invalid-session-url="/sessionTimeout.jsp" />
  
 </http>

 這樣一來,spring security3就會認為根本不需要對任何的URL或Action進行檢測(注意上面程式碼中被註釋掉的4條配置)。 哈哈,當時這個問題深深動搖了我對Spring security的信心,花費了這麼多天的精力,卻是這樣的結果,當時就在考慮是否有更好的替代品。有點崩潰啊。 還好,深深地求知慾和征服欲讓我堅持下來了。
    哈哈,這算不算Spring Security的一個Bug呢?沒有任何的許可權與資源的配置,就認為登入後的使用者具有訪問任何資源的許可權,說起來有點可怕哈。

    當然,當我將上述程式碼中被註釋的4條配置放開後,Spring security奇蹟般的恢復了活力。

    接下來實現了jsp型URL的攔截之後,我又遇見了不能攔截action的情況,不過經過多次的配置和重啟服務試驗,終於發現,在配置Action與許可權時,一定要在Action的路徑前面加“/”斜槓,否則,Spring Security就會對該請求的URL熟視無睹,無視它的存在,即使你在Action的前後加上*號進行匹配也不會起任何作用,哈哈,不禁慨嘆Spring Security的牛脾氣。


第二種方法BTW

    順便提一下子,Spring Security3需要配置的過濾器是雙重的,首先在web.xml中配置一個過濾器代理,參見上述web.xml中的springSecurityFilterChain配置。
    我們通常設定過濾的url模式為/*,就是說任何的url訪問都要進行過濾,工作量有點大哈。當然我們可以為之設定不同的過濾url模式,比如.action、.do、.jsp等。這樣的話,遇到.action或.jsp或.do結尾的url訪問,Spring Security就會突然站出來打截,若是其他的訪問,Spring Security就會揮一揮手,瀟灑地讓你路過。
所以說,這個過濾器主要對大的方面進行攔截,一些細小的活兒,還是要交給第二重過濾器。 就是說,這第一重過濾器是個總代理,他威武地管理著一個過濾器鏈。

    那麼這第二重過濾器的配置,就是那些所謂的過濾器鏈,分別包括“記住我”、“登入”、“登出”、“url訪問”等的過濾器,這個過濾器依順序排開,形成一個過濾鏈條。具體攔截我們明細Url的是一個叫做FilterInterCeptor的夥計,我認為這個傢伙是在整個過濾器鏈條中是最重要的一個,因為我們登入系統之後,要訪問的任何資源都必須經得他的同意。 那麼這第二重鏈條就設定在applicationContext-security.xml檔案中的<http>元素下面。
    什麼,你看不到? 忘記告訴你了,從spring security2開始,就使用了名稱空間,若你在<http>中設定了auto="true",Spring Security就會在服務啟動時自動載入
所有的過濾器鏈,省事了吧!

第三種方法

    當然,spring security3畢竟是西方國家的東西,以英文為主,使用習慣和文化的差異共存,況且為了適應大多數Web應用的許可權管理,作者將Spring Security3打造的精簡而靈活。精簡指Spring Security3對使用者和許可權的表設計的非常簡單,並且沒有采用資料庫來管理資源(URL)。這樣的話,對於我們國人使用者來說,是個很大的遺憾,這個遺憾甚至能夠影響到我們對安全框架的選型。你想啊,在國內大多數專案中,均設定了比較複雜的許可權控制,一般就會涉及到使用者、角色、許可權、資源4張表,若要加上4張表之間的對應關係表3張,得有7張表才行。

    得7張表才行,但是Spring Security3才給我們提供了2張最簡潔的表,這足以不能完成國人使用者的專案應用。那麼在對Spring Security3一無所知的情況下,
我們很容易就會放棄對該安全框架的選型。

    還好,Spring Security3提供了靈活的擴充套件方法。具體應該擴充套件哪些類呢? 或者到底Spring Security3工作的流程如何,你不妨參看下面一篇文章,就會獲得
一些啟示,網址為:http://www.blogjava.net/youxia/archive/2008/12/07/244883.html , 哈哈,謝謝分享。

    不過我得提一下,原文的作者為了考驗你的耐性和自信心,故意在程式碼裡面賣了幾點小小的關子,因此若是完全按照作者的原文程式碼裝配起來的許可權系統,是不會那麼順利地工作的,天下似乎真是沒有不花費力氣的午餐!在裝配完成後,我也是經過九九八十一難的折磨,在使用者、角色、許可權、資源的
“天下黃河九曲十八彎”裡面盤旋迂迴,終於到達了成功的彼岸。至此才對Spring Security有了更深層次的理解,更加佩服作者的良苦用心。 哈哈。

     並擴充套件了User類以增加其相關的各類其他資訊(如Email,職務,所在單位id等)。


相關的程式碼如下(包含5個關鍵類):

/*
 * @(#) MyFilterSecurityInterceptor.java  2011-3-23 上午07:53:03
 *
 * Copyright 2011 by Sparta 
 */

package avatar.base.security;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

/** *//**
 * 該過濾器的主要作用就是通過spring著名的IoC生成securityMetadataSource。
 * securityMetadataSource相當於本包中自定義的MyInvocationSecurityMetadataSourceService。
 * 該MyInvocationSecurityMetadataSourceService的作用提從資料庫提取許可權和資源,裝配到HashMap中,
 * 供Spring Security使用,用於許可權校驗。
 * @author sparta 11/3/29
 *
 */

public class MyFilterSecurityInterceptor 
 extends AbstractSecurityInterceptor
 implements Filter{
 

 private FilterInvocationSecurityMetadataSource securityMetadataSource;
 
 public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain)
 throws IOException, ServletException{
  
  FilterInvocation fi = new FilterInvocation( request, response, chain );
  invoke(fi);
  
 }
 
 public FilterInvocationSecurityMetadataSource getSecurityMetadataSource(){
  return this.securityMetadataSource;
 }
 
 public Class<? extends Object> getSecureObjectClass(){
  return FilterInvocation.class;
 }

 
 public void invoke( FilterInvocation fi ) throws IOException, ServletException{
  
  InterceptorStatusToken  token = super.beforeInvocation(fi);
  
  try{
   fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
  }finally{
   super.afterInvocation(token, null);
  }
  
 }
  
 
 @Override
 public SecurityMetadataSource obtainSecurityMetadataSource(){
  return this.securityMetadataSource;
 }
 
 
 public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource){
  this.securityMetadataSource = securityMetadataSource;
 }
 
 
 public void destroy(){
  
 }
 
 public void init( FilterConfig filterconfig ) throws ServletException{
  
 }
 
 
}

 

/**//*
 * @(#) MyInvocationSecurityMetadataSourceService.java  2011-3-23 下午02:58:29
 *
 * Copyright 2011 by Sparta 
 */

package avatar.base.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;
import org.springframework.stereotype.Service;

import avatar.base.security.dao.PubAuthoritiesResourcesHome;

/** *//**
 * 最核心的地方,就是提供某個資源對應的許可權定義,即getAttributes方法返回的結果。 此類在初始化時,應該取到所有資源及其對應角色的定義。
 * 
 */
@Service
public class MyInvocationSecurityMetadataSourceService implements
  FilterInvocationSecurityMetadataSource {

 @Autowired
 private PubAuthoritiesResourcesHome pubAuthoritiesResourcesHome;

 private UrlMatcher urlMatcher = new AntUrlPathMatcher();

 private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

 public MyInvocationSecurityMetadataSourceService() {
  loadResourceDefine();
 }

 private void loadResourceDefine() {
  ApplicationContext context = new ClassPathXmlApplicationContext(
    "classpath:applicationContext.xml");

  SessionFactory sessionFactory = (SessionFactory) context
    .getBean("sessionFactory");

  Session session = sessionFactory.openSession();

  String username = "";
  String sql = "";

  // 在Web伺服器啟動時,提取系統中的所有許可權。
  sql = "select authority_name from pub_authorities";

  List<String> query = session.createSQLQuery(sql).list();

  /**//*
   * 應當是資源為key, 許可權為value。 資源通常為url, 許可權就是那些以ROLE_為字首的角色。 一個資源可以由多個許可權來訪問。
   * sparta
   */
  resourceMap = new HashMap<String, Collection<ConfigAttribute>>();

  for (String auth : query) {
   ConfigAttribute ca = new SecurityConfig(auth);

   List<String> query1 = session
     .createSQLQuery(
       "select b.resource_string "
         + "from Pub_Authorities_Resources a, Pub_Resources b, "
         + "Pub_authorities c where a.resource_id = b.resource_id "
         + "and a.authority_id=c.authority_id and c.Authority_name='"
         + auth + "'").list();

   for (String res : query1) {
    String url = res;
    
    /**//*
     * 判斷資原始檔和許可權的對應關係,如果已經存在相關的資源url,則要通過該url為key提取出許可權集合,將許可權增加到許可權集合中。
     * sparta
     */
    if (resourceMap.containsKey(url)) {

     Collection<ConfigAttribute> value = resourceMap.get(url);
     value.add(ca);
     resourceMap.put(url, value);
    } else {
     Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
     atts.add(ca);
     resourceMap.put(url, atts);
    }

   }

  }

 }

 @Override
 public Collection<ConfigAttribute> getAllConfigAttributes() {

  return null;
 }

 // 根據URL,找到相關的許可權配置。
 @Override
 public Collection<ConfigAttribute> getAttributes(Object object)
   throws IllegalArgumentException {

  // object 是一個URL,被使用者請求的url。
  String url = ((FilterInvocation) object).getRequestUrl();
  
        int firstQuestionMarkIndex = url.indexOf("?");

        if (firstQuestionMarkIndex != -1) {
            url = url.substring(0, firstQuestionMarkIndex);
        }

  Iterator<String> ite = resourceMap.keySet().iterator();

  while (ite.hasNext()) {
   String resURL = ite.next();
   
   if (urlMatcher.pathMatchesUrl(url, resURL)) {

    return resourceMap.get(resURL);
   }
  }

  return null;
 }

 @Override
 public boolean supports(Class<?> arg0) {

  return true;
 }

}


/**//*
 * @(#) MyUserDetailsService.java  2011-3-23 上午09:04:31
 *
 * Copyright 2011 by Sparta 
 */

package avatar.base.security;


import java.util.ArrayList;
import java.util.Collection;


import javax.sql.DataSource;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import avatar.base.security.dao.PubAuthoritiesResourcesHome;
import avatar.base.security.dao.PubUsersHome;


/** *//**
 *該類的主要作用是為Spring Security提供一個經過使用者認證後的UserDetails。
 *該UserDetails包括使用者名稱、密碼、是否可用、是否過期等資訊。
 *sparta 11/3/29
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

 @Autowired
 private PubUsersHome pubUsersHome;
 
 @Autowired
 private PubAuthoritiesResourcesHome pubAuthoritiesResourcesHome;
 
 @Autowired
 private DataSource dataSource;
 
 @Autowired
 private UserCache userCache;

 @Override
 public UserDetails loadUserByUsername(String username)
   throws UsernameNotFoundException, DataAccessException {
  
  Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
  
  
  //得到使用者的許可權
  auths = pubUsersHome.loadUserAuthoritiesByName( username );
  
  String password = null;
  
  //取得使用者的密碼
  password = pubUsersHome.getPasswordByUsername( username );  
   
  return new User( username, password, true, "", true, true, true, auths);
 }
  
 //set PubUsersHome
 public void setPubUsersHome( PubUsersHome pubUsersHome ){
  this.pubUsersHome = pubUsersHome;
  
 }
 
 public PubUsersHome getPubUsersHome(){
  return pubUsersHome;
 }
 
 
 //set PubAuthoritiesResourcesHome
 public void setPubAuthoritiesResourcesHome( PubAuthoritiesResourcesHome pubAuthoritiesResourcesHome ){
  this.pubAuthoritiesResourcesHome = pubAuthoritiesResourcesHome;
  
 }
 
 public PubAuthoritiesResourcesHome getPubAuthoritiesResourcesHome(){
  return pubAuthoritiesResourcesHome;
  
 }
 
 //set DataSource
 public void setDataSource( DataSource dataSource ){
  this.dataSource = dataSource;
 }
 
 public DataSource getDataSource(){
  return dataSource;
 }
 
 //設定使用者快取功能。
    public void setUserCache(UserCache userCache) {
        this.userCache = userCache;
    }
    
    public UserCache getUserCache(){
     return this.userCache;
    }
 
}

/**//*
 * @(#) MyAccessDecisionManager.java  2011-3-23 下午04:41:12
 *
 * Copyright 2011 by Sparta 
 */

package avatar.base.security;

import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

/** *//**
 *AccessdecisionManager在Spring security中是很重要的。
 *
 *在驗證部分簡略提過了,所有的Authentication實現需要儲存在一個GrantedAuthority物件陣列中。 
 *這就是賦予給主體的許可權。 GrantedAuthority物件通過AuthenticationManager
 *儲存到 Authentication物件裡,然後從AccessDecisionManager讀出來,進行授權判斷。 
 *
 *Spring Security提供了一些攔截器,來控制對安全物件的訪問許可權,例如方法呼叫或web請求。 
 *一個是否允許執行呼叫的預呼叫決定,是由AccessDecisionManager實現的。 
 *這個 AccessDecisionManager 被AbstractSecurityInterceptor呼叫,
 *它用來作最終訪問控制的決定。 這個AccessDecisionManager介面包含三個方法: 
 *
 void decide(Authentication authentication, Object secureObject,
    List<ConfigAttributeDefinition> config) throws AccessDeniedException;
 boolean supports(ConfigAttribute attribute);
 boolean supports(Class clazz);
 
  從第一個方法可以看出來,AccessDecisionManager使用方法引數傳遞所有資訊,這好像在認證評估時進行決定。 
  特別是,在真實的安全方法期望呼叫的時候,傳遞安全Object啟用那些引數。 
  比如,讓我們假設安全物件是一個MethodInvocation。 
  很容易為任何Customer引數查詢MethodInvocation,
  然後在AccessDecisionManager裡實現一些有序的安全邏輯,來確認主體是否允許在那個客戶上操作。 
  如果訪問被拒絕,實現將丟擲一個AccessDeniedException異常。

  這個 supports(ConfigAttribute) 方法在啟動的時候被
  AbstractSecurityInterceptor呼叫,來決定AccessDecisionManager
  是否可以執行傳遞ConfigAttribute。 
  supports(Class)方法被安全攔截器實現呼叫,
  包含安全攔截器將顯示的AccessDecisionManager支援安全物件的型別。
 */
public class MyAccessDecisionManager implements AccessDecisionManager {
 
 public void decide( Authentication authentication, Object object, 
   Collection<ConfigAttribute> configAttributes) 
  throws AccessDeniedException, InsufficientAuthenticationException{
  
  if( configAttributes == null ) {
   return ;
  }
  
  Iterator<ConfigAttribute> ite = configAttributes.iterator();
  
  while( ite.hasNext()){
   
   ConfigAttribute ca = ite.next();
   String needRole = ((SecurityConfig)ca).getAttribute();
   
   //ga 為使用者所被賦予的許可權。 needRole 為訪問相應的資源應該具有的許可權。
   for( GrantedAuthority ga: authentication.getAuthorities()){
    
    if(needRole.trim().equals(ga.getAuthority().trim())){

     return;
    }
    
   }
   
  }
  
  throw new AccessDeniedException("");
  
 }
 
 public boolean supports( ConfigAttribute attribute ){
  
  return true;

 }
 
 public boolean supports(Class<?> clazz){
  return true;

 }
 

}

資料庫的SQL及預置資料:
prompt PL/SQL Developer import file
prompt Created on 2011年6月1日 by Administrator
set feedback off
set define off
prompt Creating SYS_AUTHORITIES
create table SYS_AUTHORITIES
(
  AUTHORITY_ID   VARCHAR2(32) not null,
  AUTHORITY_NAME VARCHAR2(40),
  AUTHORITY_DESC VARCHAR2(100),
  ENABLED        NUMBER(1),
  ISSYS          NUMBER(1),
  MODULE         VARCHAR2(4)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_AUTHORITIES
  is '許可權表';
comment on column SYS_AUTHORITIES.MODULE
  is '所屬的子系統,比如平臺裡面包括10個系統,分別為成本、作業、集輸等。';
alter table SYS_AUTHORITIES
  add constraint PK_PUB_AUTHORITIES primary key (AUTHORITY_ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );

prompt Creating SYS_RESOURCES
create table SYS_RESOURCES
(
  RESOURCE_ID     VARCHAR2(32) not null,
  RESOURCE_NAME   VARCHAR2(100),
  RESOURCE_DESC   VARCHAR2(100),
  RESOURCE_TYPE   VARCHAR2(40),
  RESOURCE_STRING VARCHAR2(200),
  PRIORITY        NUMBER(1),
  ENABLED         NUMBER(1),
  ISSYS           NUMBER(1),
  MODULE          VARCHAR2(4)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_RESOURCES
  is '資源表';
comment on column SYS_RESOURCES.PRIORITY
  is '(暫不用,保留)';
comment on column SYS_RESOURCES.MODULE
  is '所屬的子系統,比如平臺裡面包括10個系統,分別為成本、作業、集輸等。 (暫不用,保留)';
alter table SYS_RESOURCES
  add constraint PK_PUB_RESOURCES primary key (RESOURCE_ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );

prompt Creating SYS_AUTHORITIES_RESOURCES
create table SYS_AUTHORITIES_RESOURCES
(
  ID           NUMBER(13) not null,
  AUTHORITY_ID VARCHAR2(32),
  RESOURCE_ID  VARCHAR2(32),
  ENABLED      NUMBER(1)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_AUTHORITIES_RESOURCES
  is '許可權資源表';
alter table SYS_AUTHORITIES_RESOURCES
  add constraint PK_PUB_AUTHORITIES_RE primary key (ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
alter table SYS_AUTHORITIES_RESOURCES
  add constraint FK_PUB_AUTHORITIES_RE_AU foreign key (AUTHORITY_ID)
  references SYS_AUTHORITIES (AUTHORITY_ID);
alter table SYS_AUTHORITIES_RESOURCES
  add constraint FK_PUB_AUTHORITIES_RE_RE foreign key (RESOURCE_ID)
  references SYS_RESOURCES (RESOURCE_ID);

prompt Creating SYS_ROLES
create table SYS_ROLES
(
  ROLE_ID   VARCHAR2(32) not null,
  ROLE_NAME VARCHAR2(40),
  ROLE_DESC VARCHAR2(100),
  ENABLED   NUMBER(1),
  ISSYS     NUMBER(1),
  MODULE    VARCHAR2(4)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_ROLES
  is '角色表';
comment on column SYS_ROLES.MODULE
  is '所屬的子系統,比如平臺裡面包括10個系統,分別為成本、作業、集輸等。';
alter table SYS_ROLES
  add constraint PK_PUB_ROLES primary key (ROLE_ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );

prompt Creating SYS_ROLES_AUTHORITIES
create table SYS_ROLES_AUTHORITIES
(
  ID           NUMBER(13) not null,
  ROLE_ID      VARCHAR2(32),
  AUTHORITY_ID VARCHAR2(32),
  ENABLED      NUMBER(1)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_ROLES_AUTHORITIES
  is '角色許可權表';
alter table SYS_ROLES_AUTHORITIES
  add constraint PK_PUB_ROLES_AUTHORITY primary key (ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
alter table SYS_ROLES_AUTHORITIES
  add constraint FK_PUB_ROLES_AUTHORITIES_AU foreign key (AUTHORITY_ID)
  references SYS_AUTHORITIES (AUTHORITY_ID);
alter table SYS_ROLES_AUTHORITIES
  add constraint FK_PUB_ROLES_AUTHORITIES_ROLES foreign key (ROLE_ID)
  references SYS_ROLES (ROLE_ID);

prompt Creating SYS_USERS
create table SYS_USERS
(
  USER_ID       VARCHAR2(32) not null,
  USER_ACCOUNT  VARCHAR2(30),
  USER_NAME     VARCHAR2(40),
  USER_PASSWORD VARCHAR2(100),
  USER_DESC     VARCHAR2(100),
  ENABLED       NUMBER(1),
  ISSYS         NUMBER(1),
  USER_DEPT     VARCHAR2(20),
  USER_DUTY     VARCHAR2(10),
  SUB_SYSTEM    VARCHAR2(30)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_USERS
  is '使用者表';
comment on column SYS_USERS.USER_PASSWORD
  is '該密碼是經加鹽值加密的,格式為password{username}。 比如使用者的密碼為user,使用者名稱為user,那麼通過MD5進行加密的串為: user{user}';
comment on column SYS_USERS.ISSYS
  is '是否是超級使用者';
comment on column SYS_USERS.USER_DEPT
  is '所在單位';
comment on column SYS_USERS.USER_DUTY
  is '經理或主任';
comment on column SYS_USERS.SUB_SYSTEM
  is '該使用者所負責的各子系統,可多個,中間用逗號分隔。(目前暫未用,作為保留欄位)';
alter table SYS_USERS
  add constraint PK_PUB_USERS primary key (USER_ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );

prompt Creating SYS_USERS_ROLES
create table SYS_USERS_ROLES
(
  ID      NUMBER(13) not null,
  USER_ID VARCHAR2(32),
  ROLE_ID VARCHAR2(32),
  ENABLED NUMBER(1)
)
tablespace SCJD
  pctfree 10
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
comment on table SYS_USERS_ROLES
  is '使用者角色表';
alter table SYS_USERS_ROLES
  add constraint PK_PUB_USERS_ROLES primary key (ID)
  using index 
  tablespace SCJD
  pctfree 10
  initrans 2
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
alter table SYS_USERS_ROLES
  add constraint FK_USERS_ROLES_ROLES foreign key (ROLE_ID)
  references SYS_ROLES (ROLE_ID);
alter table SYS_USERS_ROLES
  add constraint FK_USERS_ROLES_USERS foreign key (USER_ID)
  references SYS_USERS (USER_ID);

prompt Disabling triggers for SYS_AUTHORITIES
alter table SYS_AUTHORITIES disable all triggers;
prompt Disabling triggers for SYS_RESOURCES
alter table SYS_RESOURCES disable all triggers;
prompt Disabling triggers for SYS_AUTHORITIES_RESOURCES
alter table SYS_AUTHORITIES_RESOURCES disable all triggers;
prompt Disabling triggers for SYS_ROLES
alter table SYS_ROLES disable all triggers;
prompt Disabling triggers for SYS_ROLES_AUTHORITIES
alter table SYS_ROLES_AUTHORITIES disable all triggers;
prompt Disabling triggers for SYS_USERS
alter table SYS_USERS disable all triggers;
prompt Disabling triggers for SYS_USERS_ROLES
alter table SYS_USERS_ROLES disable all triggers;
prompt Disabling foreign key constraints for SYS_AUTHORITIES_RESOURCES
alter table SYS_AUTHORITIES_RESOURCES disable constraint FK_PUB_AUTHORITIES_RE_AU;
alter table SYS_AUTHORITIES_RESOURCES disable constraint FK_PUB_AUTHORITIES_RE_RE;
prompt Disabling foreign key constraints for SYS_ROLES_AUTHORITIES
alter table SYS_ROLES_AUTHORITIES disable constraint FK_PUB_ROLES_AUTHORITIES_AU;
alter table SYS_ROLES_AUTHORITIES disable constraint FK_PUB_ROLES_AUTHORITIES_ROLES;
prompt Disabling foreign key constraints for SYS_USERS_ROLES
alter table SYS_USERS_ROLES disable constraint FK_USERS_ROLES_ROLES;
alter table SYS_USERS_ROLES disable constraint FK_USERS_ROLES_USERS;
prompt Deleting SYS_USERS_ROLES
delete from SYS_USERS_ROLES;
commit;
prompt Deleting SYS_USERS
delete from SYS_USERS;
commit;
prompt Deleting SYS_ROLES_AUTHORITIES
delete from SYS_ROLES_AUTHORITIES;
commit;
prompt Deleting SYS_ROLES
delete from SYS_ROLES;
commit;
prompt Deleting SYS_AUTHORITIES_RESOURCES
delete from SYS_AUTHORITIES_RESOURCES;
commit;
prompt Deleting SYS_RESOURCES
delete from SYS_RESOURCES;
commit;
prompt Deleting SYS_AUTHORITIES
delete from SYS_AUTHORITIES;
commit;
prompt Loading SYS_AUTHORITIES
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('1303910437484', 'AUTH_xxx', 'xxx', null, null, '01');
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('AUTH_LOGIN4', 'AUTH_LOGIN', '登入', 1, 0, '01');
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('AUTH_AFTERLOGINWELCOME5', 'AUTH_AFTERLOGINWELCOME', '登入後歡迎介面', 1, 0, '01');
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('AUTH_XTSZ_DEPT1', 'AUTH_XTSZ_DEPT', '單位設定', 1, 0, '01');
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('AUTH_XTSZ_USER2', 'AUTH_XTSZ_USER', '使用者設定、橫向查詢', 1, 0, '01');
insert into SYS_AUTHORITIES (AUTHORITY_ID, AUTHORITY_NAME, AUTHORITY_DESC, ENABLED, ISSYS, MODULE)
values ('AUTH_NODE_MGR3', 'AUTH_NODE_MGR', '節點管理、縱向查詢', 1, 0, '01');
commit;
prompt 6 records loaded
prompt Loading SYS_RESOURCES
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('1303909883031', 'ff', 'ff', 'action', 'b.jsp', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('1303909847687', 'ff1', 'ff1', 'action', 'b.jsp', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('node_mgr3', 'node_mgr', '節點管理', 'url', '/*/*/Tree.jsp', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('login4', 'login', '登入', 'url', '/login.jsp', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('index5', 'index', '登入後歡迎頁面', 'url', '/index.jsp', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('resources_mgr', 'resources_mgr', '資源管理', 'action', '/managerResource', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('horizontal_qry6', 'horizontal_qry', '橫向查詢', 'action', '/horizontalQuery', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('vertical_qry7', 'vertical_qry', '縱向查詢', 'action', '/verticalQuery', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('dep_mgr1', 'dep_mgr', '單位管理', 'action', '/UnitsManager', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('user_mgr2', 'user_mgr', '使用者管理', 'action', '/managerUser', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('authority_mgr', 'authority_mgr', '許可權管理', 'action', '/managerAuthority', null, 1, 0, null);
insert into SYS_RESOURCES (RESOURCE_ID, RESOURCE_NAME, RESOURCE_DESC, RESOURCE_TYPE, RESOURCE_STRING, PRIORITY, ENABLED, ISSYS, MODULE)
values ('role_mgr', 'role_mgr', '角色管理', 'action', '/managerRole', null, null, null, null);
commit;
prompt 12 records loaded
prompt Loading SYS_AUTHORITIES_RESOURCES
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (1, 'AUTH_AFTERLOGINWELCOME5', 'index5', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (2, 'AUTH_LOGIN4', 'login4', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (3, 'AUTH_NODE_MGR3', 'node_mgr3', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (4, 'AUTH_XTSZ_DEPT1', 'dep_mgr1', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (5, 'AUTH_XTSZ_USER2', 'user_mgr2', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (7, 'AUTH_XTSZ_USER2', 'horizontal_qry6', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (8, 'AUTH_XTSZ_DEPT1', 'vertical_qry7', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (12, 'AUTH_XTSZ_USER2', 'role_mgr', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (10, 'AUTH_XTSZ_USER2', 'resources_mgr', 1);
insert into SYS_AUTHORITIES_RESOURCES (ID, AUTHORITY_ID, RESOURCE_ID, ENABLED)
values (11, 'AUTH_XTSZ_USER2', 'authority_mgr', 1);
commit;
prompt 10 records loaded
prompt Loading SYS_ROLES
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('1303463518765', 'ROLE_dd1', 'dd1', 1, 0, '01');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('1303463949640', 'ROLE_rr1', 'rr1', 1, 0, '02');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_PLATFORMADMIN1', 'ROLE_PLATFORMADMIN', '可管理整個平臺的使用者、單位設定。', 1, 1, '01');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_USER2', 'ROLE_USER', '普通使用者', 1, 0, '01');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_LOGINTOWELCOME4', 'ROLE_LOGINTOWELCOME', '僅登入到歡迎介面!', 1, 0, '01');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_SYSADMIN3', 'ROLE_SYSADMIN', '可管理本系統的使用者、單位設定。', 1, 0, '01');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_WORK', 'ROLE_WORK', '作業子系統的角色(試驗)', 1, 0, '02');
insert into SYS_ROLES (ROLE_ID, ROLE_NAME, ROLE_DESC, ENABLED, ISSYS, MODULE)
values ('ROLE_LOGIN', 'ROLE_LOGIN', '系統登入', 1, 0, '01');
commit;
prompt 8 records loaded
prompt Loading SYS_ROLES_AUTHORITIES
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1, 'ROLE_LOGINTOWELCOME4', 'AUTH_AFTERLOGINWELCOME5', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (2, 'ROLE_PLATFORMADMIN1', 'AUTH_AFTERLOGINWELCOME5', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (3, 'ROLE_PLATFORMADMIN1', 'AUTH_LOGIN4', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (4, 'ROLE_PLATFORMADMIN1', 'AUTH_NODE_MGR3', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (5, 'ROLE_PLATFORMADMIN1', 'AUTH_XTSZ_DEPT1', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (6, 'ROLE_PLATFORMADMIN1', 'AUTH_XTSZ_USER2', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (7, 'ROLE_SYSADMIN3', 'AUTH_XTSZ_DEPT1', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (8, 'ROLE_SYSADMIN3', 'AUTH_XTSZ_USER2', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (9, 'ROLE_USER2', 'AUTH_LOGIN4', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (10, 'ROLE_LOGINTOWELCOME4', 'AUTH_LOGIN4', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (11, 'ROLE_USER2', 'AUTH_AFTERLOGINWELCOME5', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463962718, '1303463949640', 'AUTH_LOGIN4', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463972234, 'ROLE_WORK', 'AUTH_LOGIN4', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463972235, 'ROLE_WORK', 'AUTH_AFTERLOGINWELCOME5', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463972250, 'ROLE_WORK', 'AUTH_XTSZ_DEPT1', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463972251, 'ROLE_WORK', 'AUTH_XTSZ_USER2', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303463972265, 'ROLE_WORK', 'AUTH_NODE_MGR3', 1);
insert into SYS_ROLES_AUTHORITIES (ID, ROLE_ID, AUTHORITY_ID, ENABLED)
values (1303287600015, 'ROLE_LOGIN', 'AUTH_LOGIN4', 1);
commit;
prompt 18 records loaded
prompt Loading SYS_USERS
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304494573750', 'lxb', 'lxb', 'c7d3f4c857bc8c145d6e5d40c1bf23d9', null, 1, 0, '10011001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304490737406', 'lxb', 'lxb', 'c7d3f4c857bc8c145d6e5d40c1bf23d9', null, 1, 0, '10011001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304574079546', 'ddd', 'ddd', '0a4f6a961276619f7f91356bcba5a746', null, 0, 0, null, null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304573363921', 'lxb', '盧小兵', '09eb37d219cfa835db40e5ab587f7082', '普通僅登入到歡迎介面!', 0, 0, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304573484515', 'lll', 'lll', '47acedc22cef8c3762c21a435e262d67', null, 1, 0, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('admin1', 'admin', '系統管理員', 'ceb4f32325eda6142bd65215f4c0f371', '超級系統管理員', 1, 1, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('user2', 'user', '普通使用者', '47a733d60998c719cf3526ae7d106d13', '普通使用者', 1, 0, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('sysUser3', 'sysUser', '系統設定維護', '8f0295328c34f8eedc2362e9f4a10b7e', '系統設定使用者', 1, 0, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('lxb4', 'lxb', '盧小兵', 'c7d3f4c857bc8c145d6e5d40c1bf23d9', '普通僅登入到歡迎介面!', 1, 0, '1001', null, '01');
insert into SYS_USERS (USER_ID, USER_ACCOUNT, USER_NAME, USER_PASSWORD, USER_DESC, ENABLED, ISSYS, USER_DEPT, USER_DUTY, SUB_SYSTEM)
values ('1304566319625', 'lxb5', 'lx5', '1abe40ed6d0da1c834586e8ecef61fe7', null, 0, 0, '10011001', null, '01');
commit;
prompt 10 records loaded
prompt Loading SYS_USERS_ROLES
insert into SYS_USERS_ROLES (ID, USER_ID, ROLE_ID, ENABLED)
values (1, 'admin1', 'ROLE_PLATFORMADMIN1', 1);
insert into SYS_USERS_ROLES (ID, USER_ID, ROLE_ID, ENABLED)
values (2, 'sysUser3', 'ROLE_SYSADMIN3', 1);
insert into SYS_USERS_ROLES (ID, USER_ID, ROLE_ID, ENABLED)
values (3, 'user2', 'ROLE_USER2', 1);
insert into SYS_USERS_ROLES (ID, USER_ID, ROLE_ID, ENABLED)
values (4, 'lxb4', 'ROLE_LOGINTOWELCOME4', 1);
insert into SYS_USERS_ROLES (ID, USER_ID, ROLE_ID, ENABLED)
values (5, '1304573484515', '1303463518765', null);
commit;
prompt 5 records loaded
prompt Enabling foreign key constraints for SYS_AUTHORITIES_RESOURCES
alter table SYS_AUTHORITIES_RESOURCES enable constraint FK_PUB_AUTHORITIES_RE_AU;
alter table SYS_AUTHORITIES_RESOURCES enable constraint FK_PUB_AUTHORITIES_RE_RE;
prompt Enabling foreign key constraints for SYS_ROLES_AUTHORITIES
alter table SYS_ROLES_AUTHORITIES enable constraint FK_PUB_ROLES_AUTHORITIES_AU;
alter table SYS_ROLES_AUTHORITIES enable constraint FK_PUB_ROLES_AUTHORITIES_ROLES;
prompt Enabling foreign key constraints for SYS_USERS_ROLES
alter table SYS_USERS_ROLES enable constraint FK_USERS_ROLES_ROLES;
alter table SYS_USERS_ROLES enable constraint FK_USERS_ROLES_USERS;
prompt Enabling triggers for SYS_AUTHORITIES
alter table SYS_AUTHORITIES enable all triggers;
prompt Enabling triggers for SYS_RESOURCES
alter table SYS_RESOURCES enable all triggers;
prompt Enabling triggers for SYS_AUTHORITIES_RESOURCES
alter table SYS_AUTHORITIES_RESOURCES enable all triggers;
prompt Enabling triggers for SYS_ROLES
alter table SYS_ROLES enable all triggers;
prompt Enabling triggers for SYS_ROLES_AUTHORITIES
alter table SYS_ROLES_AUTHORITIES enable all triggers;
prompt Enabling triggers for SYS_USERS
alter table SYS_USERS enable all triggers;
prompt Enabling triggers for SYS_USERS_ROLES
alter table SYS_USERS_ROLES enable all triggers;
set feedback on
set define on
prompt Done.

相關配置檔案:

web.xml與第一種方法同。

applicationContext-security.xml:

<?xml version="1.0" encoding="UTF-8"?>

<b:beans xmlns="http://www.springframework.org/schema/security"
 xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.0.xsd">


 <http auto-config="true" access-denied-page="/accessDenied.jsp">
  <!-- 不要過濾圖片等靜態資源 -->
  <intercept-url pattern="/**/*.jpg" filters="none" />
  <intercept-url pattern="/**/*.png" filters="none" />
  <intercept-url pattern="/**/*.gif" filters="none" />
  <intercept-url pattern="/**/*.css" filters="none" />
  <intercept-url pattern="/**/*.js" filters="none" />
  <!-- 登入頁面和忘記密碼頁面不過濾  -->
  <intercept-url pattern="/login.jsp" filters="none" />
  <intercept-url pattern="/jsp/forgotpassword.jsp"
   filters="none" />  
  
  <form-login login-page="/login.jsp"
   authentication-failure-url="/login.jsp?error=true"
   default-target-url="/index.jsp" />

  <!-- "記住我"功能,採用持久化策略(將使用者的登入資訊存放在資料庫表中) -->
  <remember-me data-source-ref="dataSource" />
  
  <!-- 檢測失效的sessionId,超時時定位到另外一個URL -->
  <session-management invalid-session-url="/sessionTimeout.jsp" />
  
  
  <!-- 增加一個自定義的filter,放在FILTER_SECURITY_INTERCEPTOR之前,
  實現使用者、角色、許可權、資源的資料庫管理。  -->
  <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/> 
  
  
 </http>
 
 
 <!-- 一個自定義的filter,必須包含authenticationManager,
  accessDecisionManager,securityMetadataSource三個屬性。  -->
 <b:bean id="myFilter" 
  class="avatar.base.security.MyFilterSecurityInterceptor">
  <b:property name="authenticationManager" 
   ref="authenticationManager"/>
  <b:property name="accessDecisionManager" 
   ref="myAccessDecisionManager"/>
  <b:property name="securityMetadataSource" 
   ref="mySecurityMetadataSource"/>
 </b:bean>
 
 

 <!-- 注意能夠為authentication-manager 設定alias別名  -->