經過幾天的努力終于将acegi成功配好了。我使用的是acegisecurity-1.0.7,可以到http://acegisecurity.org下載下傳最新版。
首先在Web.xml中添加
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml,classpath:/applicationContext-acegi.xml</param-value>
</context-param>
<!--acegi 的filter鍊代理-->
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
applicationContext-acegi.xml
如果concurrentSessionController的exceptionIfMaximumExceeded屬性設定為true,麼一旦并發HttpSession數量超過限額,将會重定向到expiredUrl指定的路徑。exceptionIfMaximumExceeded一般設定為false. 為true時, 如果已有一個該使用者登入了,那麼在另一個地方登入該使用者将抛出異常 如果設定為false, 那麼, 如果已有一個該使用者登入了系統, 那麼在另一個地方也可以登入,登入後前者會被逼退出系統。
<bean id="concurrentSessionFilter" class="org.acegisecurity.concurrent.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry"></property>
<property name="expiredUrl">
<value>/userlogin/concurrentError.jsp</value>
</property>
</bean>
<bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl">
</bean>
<bean id="concurrentSessionController"
class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl">
<property name="maximumSessions" value="1"></property>
<property name="sessionRegistry" ref="sessionRegistry"></property>
<property name="exceptionIfMaximumExceeded" value="false"></property>
</bean>
設定一個安全上下文。其中HttpSessionIntegrationFilter适用于大多數情形。它将Authentication對象儲存在HTTP會話中,使之能夠跨越多個請求。
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
在做認證時可以從資料庫中讀取帳号密碼,關鍵在<bean id="SecurityUserDetailService" class="com.jlcatvum.web.dao.SecurityUserDetailService">
<property name="usersByUsernameQuery">
<value>?</value>
</property>
</bean>這個SecurityUserDetailService就是讀取自己資料庫的bean。
<!-- 表單認證處理filter -->
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationFailureUrl" value="/userlogin/userLogin.jsp?login_error=1" /><!-- 認證失敗後轉向的頁面 -->
<property name="defaultTargetUrl" value="/form/Frameset.jsp" /> <!-- 認證成功後轉向的頁面 -->
<property name="filterProcessesUrl" value="/j_acegi_security_check" />
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>
<!-- 認證管理器 -->
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers"><!-- 可有多個認證提供器,其中一個證通過就可以了 -->
<list>
<ref local="daoAuthenticationProvider" />
<ref local="anonymousAuthenticationProvider" />
<ref local="rememberMeAuthenticationProvider" />
</list>
</property>
<property name="sessionController"
ref="concurrentSessionController">
</property>
</bean>
<!-- 定義使用者資料讀取方式-->
<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="SecurityUserDetailService" />
</bean>
<!-- 自定義使用者資料,從資料庫中讀取-->
<bean id="SecurityUserDetailService" class="com.jlcatvum.web.dao.SecurityUserDetailService">
<property name="usersByUsernameQuery">
<value>?</value>
</property>
</bean>
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<!--
======================== 匿名使用者驗證 =======================
-->
<!-- 匿名使用者登入 -->
<bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="key" value="changeThis"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<!-- 匿名驗證Provider -->
<bean id="anonymousAuthenticationProvider"
class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
<property name="key" value="javargb" />
</bean>
這是SecurityUserDetailService的代碼
package com.jlcatvum.web.dao;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.userdetails.memory.UserAttribute;
import org.acegisecurity.userdetails.memory.UserAttributeEditor;
import org.springframework.dao.DataAccessException;
import com.jlcatvum.db.table.Users;
public class SecurityUserDetailService implements UserDetailsService {
private String usersByUsernameQuery;
public UserDetails loadUserByUsername(String arg0)
throws UsernameNotFoundException, DataAccessException {
// TODO Auto-generated method stub
Users user = getUser(arg0);
// ---
if (user == null)
return null;
UserAttributeEditor configAttribEd = new UserAttributeEditor();
String userInfo = user.getPassword() + "," + user.getEnable();
//logger.info("userInfo:" + userInfo);
configAttribEd.setAsText(userInfo);
UserAttribute attr = (UserAttribute) configAttribEd.getValue();
if (attr != null) {
org.acegisecurity.userdetails.UserDetails userDetails = new User(
arg0, attr.getPassword(), attr.isEnabled(), true, true,
true, attr.getAuthorities());
//logger.info("userDetails:" + userDetails);
return userDetails;
}
return null;
}
private Users getUser(String name) {
Users list = new Users();
UserDAO userdao = new UserDAO(name);
userdao.findByName();
list = userdao.getList();
if (list != null)
return list;
else
return null;
}
public void setUsersByUsernameQuery(String usersByUsernameQuery) {
this.usersByUsernameQuery = usersByUsernameQuery;
}
public String getUsersByUsernameQuery() {
return usersByUsernameQuery;
}
}
在filterInvocationInterceptor過濾器裡設好資源的權限後,就能夠在沒有登入的情況下通路資源時跳轉到登入界面。當然在後面異常處理的過濾器中要指定跳轉的頁面。
<!--
======================== 授權 =======================
-->
<!-- 授權管理器-->
<bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><!-- 是否讓全部棄權的通過 -->
<value>false</value>
</property>
<property name="decisionVoters"><!-- 投票者們 -->
<ref bean="roleVoter"/>
</property>
</bean>
<!-- 投票者的類-->
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
<property name="rolePrefix">
<value>ROLE_</value><!-- 可以改成别的 -->
</property>
</bean>
<!--
======================== 資源權限管理 =======================
-->
<!-- 資源權限管理 -->
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<bean class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<bean class="org.acegisecurity.vote.RoleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value><!--[CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_SUPERVISOR
/form/**=IS_AUTHENTICATED_REMEMBERED
/system/**=ROLE_SUPERVISOR
/userlogin/**=IS_AUTHENTICATED_ANONYMOUSLY
/**=IS_AUTHENTICATED_ANONYMOUSLY
]]--></value>
</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="SecurityUserDetailService"/>
<property name="key" value="javargb"/>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="javargb"/>
</bean>
<!--
======================== 登出處理filter =======================
-->
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/userlogin/userLogin.jsp"/> <!-- 登出後轉向頁面 -->
<constructor-arg>
<list>
<ref bean="rememberMeServices"/>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<!--
======================== 異常處理filter =======================
-->
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/userlogin/userLogin.jsp" />
<property name="forceHttps" value="false" />
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/userlogin/accessDenied.faces" />
</bean>
</property>
</bean>