看了一段時(shí)間Acegi的文檔和例子,今天終于把這個(gè)難纏的家伙給搞定了.其實(shí)就是一些概念的理解的差別,搞得暈頭轉(zhuǎn)向的.
在網(wǎng)上找了一些文章和例子,同一個(gè)內(nèi)容卻有不同的說(shuō)法.有的說(shuō)acegi沒(méi)有角色的概念,有的說(shuō)在認(rèn)證通過(guò)后將用戶對(duì)就在角色保存在Session中.搞得很暈.
經(jīng)過(guò)幾天看源碼和例子,我覺(jué)得acegi是沒(méi)有角色的概念的.它只是判斷一個(gè)用戶有沒(méi)有操作或訪問(wèn)某一個(gè)資源的權(quán)限,如果有權(quán)限就可以訪問(wèn),沒(méi)有權(quán)限就拋出異常。這個(gè)中間沒(méi)有涉及到的角色,但是我們可以通過(guò)擴(kuò)展原有的類加入角色的概念,畢竟大多數(shù)的權(quán)限控制都有角色。(擴(kuò)展方法后面有介紹)
基本原理(我寫得比較簡(jiǎn)單,個(gè)人也只是簡(jiǎn)單應(yīng)用的程度)
1、用戶請(qǐng)求登錄,根據(jù)配置校驗(yàn)用戶名和密碼,用戶名和密碼acegi默認(rèn)是在xml文件中配置,可以通過(guò)數(shù)據(jù)庫(kù)來(lái)保存,主要是實(shí)現(xiàn)UserDetailsService.loadUserByUsername方法。這個(gè)方法返回一個(gè)org.acegisecurity.userdetails .UserDetails。org.acegisecurity.userdetails.User實(shí)現(xiàn)了UserDetails。它的構(gòu)造方法是:
User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, GrantedAuthority[] authorities)
Construct the User
with the details required by DaoAuthenticationProvider
2、Logout處理
acegi 的logout的地址是j_acegi_logout。例如:<a href="/j_acegi_logout">logout</a>。如果有web.xml的fitler-mapping中配置的不是/*,則要加入這樣代碼:
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/j_acegi_logout</url-pattern>
</filter-mapping>
在acegi配置中:
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=concurrentSessionFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
</value>
</property>
</bean>
<!-- 認(rèn)證管理器 -->
<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers"><!-- 可有多個(gè)認(rèn)證提供器,其中一個(gè)證通過(guò)就可以了 -->
<list>
<ref local="daoAuthenticationProvider" />
<!-- 匿名認(rèn)證 -->
<!-- ref local="anonymousAuthenticationProvider"/-->
<!-- ref local="rememberMeAuthenticationProvider" /-->
</list>
</property>
<property name="sessionController"
ref="concurrentSessionController" />
</bean>
<!-- 可以限制同一個(gè)用戶名在同一時(shí)刻成功登錄同一個(gè)應(yīng)用的次數(shù) -->
<bean id="concurrentSessionController"
class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl">
<!-- 每個(gè)用戶同時(shí)登陸一位 -->
<property name="maximumSessions">
<value>1</value>
</property>
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="exceptionIfMaximumExceeded" value="true" />
<!-- 默認(rèn)是false,即如果超出最大登陸用戶限制,你這個(gè)登陸還是允許的。但是其他已經(jīng)用這個(gè)用戶登陸的會(huì)有一個(gè)給強(qiáng)制OUT的。
只有是true時(shí),才會(huì)不讓你這個(gè)用戶登陸 -->
</bean>
<bean id="sessionRegistry"
class="org.acegisecurity.concurrent.SessionRegistryImpl" />
<bean id="concurrentSessionFilter"
class="org.acegisecurity.concurrent.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl">
<value>/</value>
</property>
</bean>
其中:concurrentSessionFilter,建議放在httpSessionContextIntegrationFilter的前面。這樣就可以logout了。