天天看點

用acegi作權限管理

經過幾天的努力終于将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>