JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Java Application Framework » Spring  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to topicthreaded modego to previous topicgo to next topic
己加入精華區
by caterpillar at 2007-04-03 12:35
本主題所含的標籤
無標籤
作者 第一個 Acegi 程式 [精華]
caterpillar

良葛格

版主

發文: 2613
積分: 70
於 2007-04-03 12:33 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
最近在把一些Acegi的東西整理一下…放在 這邊,陸續推出…Big Smile

=================================================
首先請先至Acegi官方網站,下載Acegi程式庫,在撰寫這份教學文件之時,所使用的版本是1.0.3。

Acegi相關類別之間的依賴關係,可以藉由IoC容器來協助建立,在這邊您可以使用 Spring 的IoC容器功能,您可以在下載的Acegi檔案中,找到acegi-security-sample-tutorial.war,將之使用解壓縮軟體解開,可以在WEB-INF\lib下,找到所需的Spring程式庫,在Acegi 1.0.3中的acegi-security-sample-tutorial.war所搭配的是Spring 1.2.8。

要完成您第一個Acegi程式,您需要以下的程式庫:
* acegi-security-1.0.3.jar
* spring-1.2.8.jar

為了在Web應用程式中,使用Acegi搭配Spring的Context資訊,來完成Acegi的依賴關係配置,您要在web.xml中設定 org.springframework.web.context.ContextLoaderListener,並在Context參數中,指定設定檔案位置與名稱,而Acegi主要透過Filter Chain來達到請求的檢查、驗證、授權、登出等動作,您可以在web.xml中如下設定:
* web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
 
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
   version="2.4">
 
    <display-name>Acegi 範例</display-name>
    
    <!-- 指定Acegi資訊的設定檔-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/acegi-config.xml</param-value>
    </context-param>
    
    <!-- Acegi 的 Filter Chain 代理 -->
    <filter>
        <filter-name>Acegi Filter Chain Proxy</filter-name>
        <filter-class>
            org.acegisecurity.util.FilterToBeanProxy
        </filter-class>
        <init-param>
            <param-name>targetClass</param-name>
                <param-value>
                    org.acegisecurity.util.FilterChainProxy
                </param-value>
        </init-param>
    </filter>
 
    <filter-mapping>
        <filter-name>Acegi Filter Chain Proxy</filter-name>
        <url-pattern>/*</url-pattern>
     </filter-mapping>

     <!-- 取得Spring的Context -->
     <listener>
         <listener-class>
             org.springframework.web.context.ContextLoaderListener
         </listener-class>
     </listener>
</web-app>


org.acegisecurity.util.FilterToBeanProxy建立 org.acegisecurity.util.FilterChainProxy實例,並將請求轉交給FilterChainProxy來處理,接下來就是配置acegi-config.xml的內容,在這邊先假設一個需求情境,您想要對Web應用程式中的/protected/下所有資源進行保護,如果使用者試圖存取/protected/下的資源,就先將其送至/acegilogin.jsp進行登入,登入成功後顯示使用者所請求的資源,使用者也可以直接連接/acegilogin.jsp,登入成功後,預設顯示/loginsuccess.jsp,您可以在acegi-config.xml中加入以下的設定:
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 驗證處理,使用表單 -->
    <bean id="authenticationProcessingFilter"
          class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> 
        <!-- 驗證管理員,處理驗證資訊提供者  -->
        <property name="authenticationManager" ref="authenticationManager"/> 
        <!-- 驗證失敗URL -->
        <property name="authenticationFailureUrl" value="/acegilogin.jsp"/> 
        <!-- 驗證成功預設URL -->
        <property name="defaultTargetUrl" value="/protected/userinfo.jsp"/> 
        <!-- 驗證處理的提交位址 -->
        <property name="filterProcessesUrl" value="/j_acegi_security_check"/> 
    </bean>        


可以看到在這邊使用了AuthenticationProcessingFilter來處理驗證,實際對使用者的驗證是交給驗證管理員,也就是authenticationManager屬性中所設定的實例,可以在acegi-config.xml中加入:
1
2
3
4
5
6
7
8
    <!-- 驗證管理員,管理驗證資訊提供者 -->
   <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> 
      <property name="providers"><!-- 可有多個提供者,其中一個驗證通過即可以了 --> 
         <list> 
            <ref local="daoAuthenticationProvider"/> 
         </list> 
      </property> 
   </bean>


驗證管理員管理驗證提供者,也就是實際提供使用者名稱、密碼、角色資訊的物件,來源可以是資料庫或設定文件中的訊息,基於來源的不同,您可以使用 org.acegisecurity.providers.dao.DaoAuthenticationProvider,並指定其 userDetailsService屬性,設定驗證訊息來源:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
   <!-- 驗證提供者,指定使用記憶體來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> 
        <property name="userDetailsService" ref="inMemoryDaoImpl"/>
   </bean> 
    
   <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">   
            <value>   
                caterpillar=123456,ROLE_SUPERVISOR
                user1=user1pwd,ROLE_USER
                user2=user2pwd,disabled,ROLE_USER    
            </value>   
        </property>   
    </bean> 


在這邊使用userMap屬性指定可以登入的使用者名稱、密碼、是否啟用、角色等資訊。

當驗證失敗會發生例外,這時需要將之送至/acegilogin.jsp,權限不符而試圖取得資源時則將之送至/accessDenied.jsp,這可以使用org.acegisecurity.ui.ExceptionTranslationFilter來達到:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <!-- 發生驗證錯誤或權限錯誤時的處理 -->
    <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> 
        <property name="authenticationEntryPoint"> 
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> 
                <property name="loginFormUrl" value="/acegilogin.jsp"/> 
                <property name="forceHttps" value="false"/> 
            </bean> 
        </property> 
        <property name="accessDeniedHandler"> 
            <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> 
                <property name="errorPage" value="/accessDenied.jsp"/> 
            </bean> 
        </property> 
    </bean>      


接下來要定義可以存取的資源,由於在這邊是針對URL進行規範,可以使用org.acegisecurity.intercept.web.FilterSecurityInterceptor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <!-- FilterSecurityInterceptor 對 URI 進行保護 -->
    <bean id="filterSecurityInterceptor"
          class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <!-- 驗證管理員 -->
        <property name="authenticationManager" ref="authenticationManager" />
        <!-- 授權管理員 -->
        <property name="accessDecisionManager" ref="accessDecisionManager" />
        <property name="objectDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /protected/**=ROLE_SUPERVISOR,ROLE_USER
            </value>
        </property>
    </bean>


FilterSecurityInteceprot需要參考至驗證管理員取得驗證訊息,以對使用者進行驗證,而是否授權則必須以投票的方式來決定,Acegi的解決方案有幾種:

1. 如果有一個同意就通過
2. 如果都同意就通過
3. 如果都不反對就通過

例如若希望/protected/下可以被使用者(USER)或管理者(SUPERVISOR)存取,採第一個方案的話則使用AffirmativeBased實作:
1
2
3
4
5
6
7
8
9
10
    <!-- 授權管理員 -->
    <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
         <!-- 是否全部棄權時視為通過 -->
         <property name="allowIfAllAbstainDecisions" value="false" />
         <property name="decisionVoters">
             <list>
                 <bean class="org.acegisecurity.vote.RoleVoter" />
             </list>
         </property>
    </bean>


RoleVoter對使用者群組中,有ROLE_作為前置文件的進投票,您也可以在設定RoleVoter實例時,使用其rolePrefix來改變前置文字。

Acegi是基於Filter Chain來完成請求的檢查、驗證、授權等動作,所以要將以上的Filter串在一起了:
1
2
3
4
5
6
7
8
9
10
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
         </value> 
      </property> 
    </bean>


所完成的acegi-config.xml完整檔案如下所示:

* acegi-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- 驗證處理,使用表單 -->
    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">  
        <!-- 驗證管理員,處理驗證資訊提供者  -->
        <property name="authenticationManager" ref="authenticationManager"/>  
        <!-- 驗證失敗URL -->
        <property name="authenticationFailureUrl" value="/acegilogin.jsp"/>  
        <!-- 驗證成功預設URL -->
        <property name="defaultTargetUrl" value="/protected/userinfo.jsp"/>  
        <!-- 驗證處理的提交位址 -->
        <property name="filterProcessesUrl" value="/j_acegi_security_check"/>  
    </bean>
 
    <!-- 驗證管理員,管理驗證資訊提供者 -->
   <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">  
      <property name="providers"><!-- 可有多個提供者,其中一個驗證通過即可以了 -->  
         <list>  
            <ref local="daoAuthenticationProvider"/>  
         </list>  
      </property>  
   </bean>
 
   <!-- 驗證提供者,指定使用記憶體來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
        <property name="userDetailsService" ref="inMemoryDaoImpl"/>
   </bean> 
     
   <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">    
            <value>    
                caterpillar=123456,ROLE_SUPERVISOR
                user1=user1pwd,ROLE_USER
                user2=user2pwd,disabled,ROLE_USER     
            </value>    
        </property>    
    </bean>     
    
    <!-- 發生驗證錯誤或權限錯誤時的處理 -->
    <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">  
        <property name="authenticationEntryPoint">  
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">  
                <property name="loginFormUrl" value="/acegilogin.jsp"/>  
                <property name="forceHttps" value="false"/>  
            </bean>  
        </property>  
        <property name="accessDeniedHandler">  
            <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">  
                <property name="errorPage" value="/accessDenied.jsp"/>  
            </bean>  
        </property>  
    </bean>    
 
    <!-- FilterSecurityInterceptor 對 URI 進行保護 -->
    <bean id="filterSecurityInterceptor"
          class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <!-- 驗證管理員 -->
        <property name="authenticationManager" ref="authenticationManager" />
        <!-- 授權管理員 -->
        <property name="accessDecisionManager" ref="accessDecisionManager" />
        <property name="objectDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /protected/**=ROLE_SUPERVISOR,ROLE_USER
            </value>
        </property>
    </bean>
    
    <!-- 授權管理員 -->
    <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
         <!-- 是否全部棄權時視為通過 -->
         <property name="allowIfAllAbstainDecisions" value="false" />
         <property name="decisionVoters">
             <list>
                 <bean class="org.acegisecurity.vote.RoleVoter" />
             </list>
         </property>
    </bean>        
    
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
         </value> 
      </property> 
    </bean>    
</beans> 


caterpillar edited on 2013-03-24 15:41
reply to postreply to post
良葛格學習筆記
作者 Re:第一個 Acegi 程式 [Re:caterpillar]
caterpillar

良葛格

版主

發文: 2613
積分: 70
於 2007-04-03 12:34 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
接下來完成必要的表單網頁,首先是/acegilogin.jsp:

* acegilogin.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
<head>
<title>Acegi 範例網頁 - 登入</title>
</head>
<body>
<h2>登入範例應用程式!</h2>
<br />
<form action="j_acegi_security_check" method="POST">
<table>
  <tr>
    <td>名稱:</td>
    <td><input type='text' name='j_username' value=''></td>
  </tr>
  <tr>
    <td>密碼:</td>
    <td><input type='password' name='j_password'></td>
  </tr>
  <tr>
    <td><input name="reset" type="reset"></td>
    <td><input name="submit" type="submit"></td>
  </tr>
</table>
</form>
</body>
</html>


j_acegi_security_check為設定文件 中authenticationProcessingFilter的filterProcessesUrl屬性所設定的名稱,而驗證時發送的使用者名稱與密碼,要以j_username與j_password請求參數送出。

如果想要在登入失敗時顯示錯誤訊息,可以檢查param.login_error是否為空,例如結合JSTL的話:
1
2
3
4
<c:if test="${not empty param.login_error}">
    <font color="red">使用者名稱或密碼錯誤,請重新登入!<BR>
    </font>
</c:if>


您也許想顯示最後一次登入失敗的使用者名稱,這個訊息是儲存在session之中,可以使用AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY作為KEY來取得這個值,例如:
1
2
3
4
5
6
7
8
9
<%@ page import="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"%>
 
...
 
<input type='text' name='j_username'
    <c:if test="${not empty param.login_error}">
        value='<%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %>'
    </c:if>
>


登入成功的話,可以顯示/WEB-INF/loginsuccess.jsp

* loginsuccess.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ page import="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"%>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
 
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登入成功</title>
    </head>
    <body>
        
    <h1>歡迎 <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %>
    </h1>
        
    </body>
</html>


接著,設置一個簡單的首頁,當使用者存取首頁時,直接轉頁至acegilogin.jsp:

* index.jsp
1
2
3
4
5
6
7
8
9
10
  <%@ page language="java" pageEncoding="UTF-8"%>  
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">  
  <html>  
  <head>  
  <META HTTP-EQUIV="Refresh" CONTENT="0;URL=acegilogin.jsp">  
  </head>  
  <body>  
        <p>載入中...</p>  
  </body>  
  </html>  


現在您可以啟動您的應用程式了,嘗試直接存取acegilogin.jsp並登入,關閉瀏覽器並清除快取,再嘗試直接存取/protected/下的資源,看看結果如何。


reply to postreply to post
良葛格學習筆記
作者 Re:第一個 Acegi 程式 [Re:caterpillar]
caterpillar

良葛格

版主

發文: 2613
積分: 70
於 2007-04-03 14:07 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
您已經可以使用Acegi來保護您所設定的資源,為了方便起見,您應該提供一個登出的鏈結,讓使用者可以登出,讓目前的對話失效。

這可以在/WEB-INF/loginsuccess.jsp上加上一個登出的鏈結,動作的目的地是j_acegi_logout:

* loginsuccess.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@ page import="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"%>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
 
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>登入成功</title>
    </head>
    <body>
        
    <h1>歡迎 <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %>
    </h1>
    <br><a href="../j_acegi_logout">登出</a>
    </body>
</html>


要進行登出,可以設定org.acegisecurity.ui.logout.LogoutFilter,指定登出後的顯示頁面,以及執行登出動作的處理者:

* acegi-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    ... 先前設定相同 
 
    <!-- 登出處理 -->  
    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">  
        <constructor-arg value="/acegilogin.jsp"/> <!-- 登出後的顯示頁面 -->  
            <constructor-arg>  
               <list>  
                   <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>  
               </list>  
        </constructor-arg>  
    </bean> 
    
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor,logoutFilter
         </value> 
      </property> 
    </bean>    
</beans>   


這樣就OK了,登入之後,您就可以看到登出的鏈結,按下該鏈結後就可自動進行登出。

如果要執行Cookies自動登入,則可以使用org.acegisecurity.ui.rememberme.RememberMeProcessingFilter,您要提供驗證管理員與RememberMeServices,並指定Cookie名稱,例如:

* acegi-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    ....
 
    <!-- 驗證管理員,管理驗證資訊提供者 -->
   <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">  
      <property name="providers"><!-- 可有多個提供者,其中一個驗證通過即可以了 -->  
         <list>  
            <ref local="daoAuthenticationProvider"/> 
            <ref local="rememberMeAuthenticationProvider"/>
         </list>  
      </property>  
   </bean>
    .....
 
    <!-- 利用cookie自動登入 -->  
    <bean id="rememberMeProcessingFilter"  
           class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">  
        <property name="authenticationManager"  ref="authenticationManager"/>  
        <property name="rememberMeServices" ref="rememberMeServices"/>  
    </bean>      
    <bean id="rememberMeServices"  
           class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">  
        <property name="userDetailsService" ref="inMemoryDaoImpl"/>  
        <property name="key" value="javauser"/>  
    </bean>
    <bean id="rememberMeAuthenticationProvider"  
           class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">  
        <property name="key" value="javauser"/>  
    </bean>   
    
    <!-- 登出處理 -->  
    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">  
        <constructor-arg value="/acegilogin.jsp"/> <!-- 登出後的顯示頁面 -->  
            <constructor-arg>  
               <list>  
                   <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>  
               </list>  
        </constructor-arg>  
    </bean> 
    
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor,
                logoutFilter,rememberMeProcessingFilter
         </value> 
      </property> 
    </bean>    
</beans>   


要進行自動登入,您必須在登入時發送_acegi_security_remember_me請求參數,例如修改acegilogin.jsp:

* acegilogin.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
<head>
<title>Acegi 範例網頁 - 登入</title>
</head>
<body>
<h2>登入範例應用程式!</h2>
<br />
<form action="j_acegi_security_check" method="POST">
<table>
  <tr>
    <td>名稱:</td>
    <td><input type='text' name='j_username' value=''></td>
  </tr>
  <tr>
    <td>密碼:</td>
    <td><input type='password' name='j_password'></td>
  </tr>
        <tr>
                <td>
                    <input type="checkbox" name="_acegi_security_remember_me">
                </td>
                <td>2周内記得我</td>
        </tr>  
  <tr>
    <td><input name="reset" type="reset"></td>
    <td><input name="submit" type="submit"></td>
  </tr>        
</table>
</form>
</body>
</html>


caterpillar edited on 2007-04-03 14:47
reply to postreply to post
良葛格學習筆記
作者 Re:第一個 Acegi 程式 [Re:caterpillar]
caterpillar

良葛格

版主

發文: 2613
積分: 70
於 2007-04-03 14:54 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
在先前的設定中,inMemoryDaoImpl將使用者訊息設定在userMap之中:
1
2
3
4
5
6
7
8
9
   <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">   
            <value>   
                caterpillar=123456,ROLE_SUPERVISOR
                user1=user1pwd,ROLE_USER
                user2=user2pwd,disabled,ROLE_USER    
            </value>   
        </property>   
    </bean>


您可以撰寫一個屬性檔案/WEB-INF/users.properties:

* users.properties
1
2
3
caterpillar=123456,ROLE_SUPERVISOR
user1=user1pwd,ROLE_USER
user2=user2pwd,disabled,ROLE_USER


然後改設定inMemoryDaoImpl的userProperties:
1
2
3
4
5
6
7
   <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
       <property name="userProperties">
           <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
               <property name="location" value="/WEB-INF/users.properties" />
           </bean>
       </property>
   </bean>


如此在需要使用者訊息時,就可以從users.properties中提取。

如果想要將使用者的相關訊息儲存在資料庫中,例如使用以下的SQL在MySQL中建立使用者訊息:

* users.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE DATABASE acegi;
USE acegi;
 
CREATE TABLE USERS(  
    USERNAME VARCHAR(50) NOT NULL PRIMARY KEY,  
    PASSWORD VARCHAR(50) NOT NULL,  
    ENABLED BIT NOT NULL
);
 
INSERT INTO USERS(username,password,enabled) values('caterpillar' ,'123456', 1);
INSERT INTO USERS(username,password,enabled) values('user1' ,'user1pwd', 1);
INSERT INTO USERS(username,password,enabled) values('user2' ,'user2pwd', 0);
 
CREATE TABLE AUTHORITIES(  
    USERNAME VARCHAR( 50 ) NOT NULL,  
    AUTHORITY VARCHAR( 50 ) NOT NULL,  
    CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME)  
);  
  
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( 'caterpillar' , 'ROLE_SUPERVISOR');
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( 'user1', 'ROLE_USER');  
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( 'user2', 'ROLE_USER');


您可以使用org.acegisecurity.userdetails.jdbc.JdbcDaoImpl作為userDetailsService,它需要一個DataSource,這可以使用Spring的DriverManagerDataSource,例如:

* acegi-config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
         <property name="driverClassName">  
             <value>com.mysql.jdbc.Driver</value>              
         </property>  
         <property name="url">  
             <value>jdbc:mysql://localhost:3306/acegi</value>  
         </property>  
         <property name="username">  
             <value>root</value>  
         </property>  
         <property name="password">  
             <value>123456</value>  
         </property>  
     </bean>  
     
    <!-- 驗證處理,使用表單 -->
    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">  
        <!-- 驗證管理員,處理驗證資訊提供者  -->
        <property name="authenticationManager" ref="authenticationManager"/>  
        <!-- 驗證失敗URL -->
        <property name="authenticationFailureUrl" value="/acegilogin.jsp"/>  
        <!-- 驗證成功預設URL -->
        <property name="defaultTargetUrl" value="/protected/loginsuccess.jsp"/>  
        <!-- 驗證處理的提交位址 -->
        <property name="filterProcessesUrl" value="/j_acegi_security_check"/>  
    </bean>
 
    <!-- 驗證管理員,管理驗證資訊提供者 -->
   <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">  
      <property name="providers"><!-- 可有多個提供者,其中一個驗證通過即可以了 -->  
         <list>  
            <ref local="daoAuthenticationProvider"/> 
            <ref local="rememberMeAuthenticationProvider"/>
         </list>  
      </property>  
   </bean>
 
   <!-- 驗證提供者,指定使用資料庫來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
        <property name="userDetailsService" ref="jdbcDaoImpl"/>
   </bean> 
 
   <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">  
       <property name="dataSource">
           <ref bean="dataSource"/> 
       </property>  
   </bean>  
    
    <!-- 發生驗證錯誤或權限錯誤時的處理 -->
    <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">  
        <property name="authenticationEntryPoint">  
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">  
                <property name="loginFormUrl" value="/acegilogin.jsp"/>  
                <property name="forceHttps" value="false"/>  
            </bean>  
        </property>  
        <property name="accessDeniedHandler">  
            <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">  
                <property name="errorPage" value="/accessDenied.jsp"/>  
            </bean>  
        </property>  
    </bean>    
 
    <!-- FilterSecurityInterceptor 對 URI 進行保護 -->
    <bean id="filterSecurityInterceptor"
          class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <!-- 驗證管理員 -->
        <property name="authenticationManager" ref="authenticationManager" />
        <!-- 授權管理員 -->
        <property name="accessDecisionManager" ref="accessDecisionManager" />
        <property name="objectDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /protected/**=ROLE_SUPERVISOR,ROLE_USER
            </value>
        </property>
    </bean>
    
    <!-- 授權管理員 -->
    <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
         <!-- 是否全部棄權時視為通過 -->
         <property name="allowIfAllAbstainDecisions" value="false" />
         <property name="decisionVoters">
             <list>
                 <bean class="org.acegisecurity.vote.RoleVoter" />
             </list>
         </property>
    </bean>        

    <!-- 利用cookie自動登入 -->  
    <bean id="rememberMeProcessingFilter"  
           class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">  
        <property name="authenticationManager"  ref="authenticationManager"/>  
        <property name="rememberMeServices" ref="rememberMeServices"/>  
    </bean>      
    <bean id="rememberMeServices"  
           class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">  
        <property name="userDetailsService" ref="jdbcDaoImpl"/>  
        <property name="key" value="javauser"/>  
    </bean>
    <bean id="rememberMeAuthenticationProvider"  
           class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">  
        <property name="key" value="javauser"/>  
    </bean>   
    
    <!-- 登出處理 -->  
    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">  
        <constructor-arg value="/acegilogin.jsp"/> <!-- 登出後的顯示頁面 -->  
            <constructor-arg>  
               <list>  
                   <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>  
               </list>  
        </constructor-arg>  
    </bean> 
    
    <!-- Filter Chain -->
     <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">  
       <property name="filterInvocationDefinitionSource">  
          <value>  
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
            PATTERN_TYPE_APACHE_ANT 
            /**=authenticationProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor,logoutFilter,rememberMeProcessingFilter
         </value> 
      </property> 
    </bean>    
</beans>   


當然,別忘了在您的Web應用程式的lib中,加入JDBC驅動程式程式庫。


caterpillar edited on 2007-04-03 17:13
reply to postreply to post
良葛格學習筆記
作者 Re:第一個 Acegi 程式 [Re:caterpillar]
nerv





發文: 25
積分: 0
於 2007-06-15 17:28 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
有沒有辦法將
1
2
3
4
5
6
7
8
9
10
<!-- 驗證提供者,指定使用資料庫來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
        <property name="userDetailsService" ref="jdbcDaoImpl"/>
   </bean> 
 
   <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">  
       <property name="dataSource">
           <ref bean="dataSource"/> 
       </property>  
   </bean> 

JdbcDaoImpl 這邊跟Hibernate 或者 iBatis 作結合?!
現有系統,已經使用iBatis。如果又想在Acegi 做資料庫的驗證,不曉得可不可以將iBatis的SqlMapClient 載入到 org.acegisecurity.userdetails.jdbc.JdbcDaoImpl 。


reply to postreply to post
作者 Re:第一個 Acegi 程式 [Re:nerv]
qrtt1





發文: 1746
積分: 31
於 2007-06-15 20:11 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
nerv wrote:
有沒有辦法將
1
2
3
4
5
6
7
8
9
10
<!-- 驗證提供者,指定使用資料庫來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
        <property name="userDetailsService" ref="jdbcDaoImpl"/>
   </bean> 
 
   <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">  
       <property name="dataSource">
           <ref bean="dataSource"/> 
       </property>  
   </bean> 

JdbcDaoImpl 這邊跟Hibernate 或者 iBatis 作結合?!
現有系統,已經使用iBatis。如果又想在Acegi 做資料庫的驗證,不曉得可不可以將iBatis的SqlMapClient 載入到 org.acegisecurity.userdetails.jdbc.JdbcDaoImpl 。


authenticationManager 的 provider 接受的值是 list
你可以加很多個 authentication provider


reply to postreply to post
蝸牛角上爭何事?石火光中寄此身,隨富隨貧且歡樂,不開口笑是癡人。
my notes
作者 Re:第一個 Acegi 程式 [Re:caterpillar]
nerv





發文: 25
積分: 0
於 2007-06-15 23:46 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
對不起,是第一次接觸Acegi。
qrtt1 您說的意思是?! 我是想把
1
2
3
4
5
6
7
8
9
10
<!-- 驗證提供者,指定使用資料庫來源中的驗證資訊 -->
   <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">  
        <property name="userDetailsService" ref="jdbcDaoImpl"/>
   </bean> 
 
   <bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">  
       <property name="dataSource">
           <ref bean="dataSource"/> 
       </property>  
   </bean> 


jdbcDaoImpl 這邊的dataSource 設定成其他的dataSource 例如SqlMapClient,
跟authenticationManager 有關西嗎?!


reply to postreply to post
作者 Re:第一個 Acegi 程式 [Re:nerv]
javaer

OMG!



發文: 87
積分: 1
於 2007-06-16 22:44 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
以你的case當然是可以
去把設定datasource的bean改一改就好了

換datasource是小意思
如果要兩個以上的datasource才需要動到多個provider


reply to postreply to post
» JWorld@TW »  Java Application Framework » Spring

reply to topicthreaded modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8