二 Acegi安全系統(tǒng)的配置?
????? Acegi 的配置看起來(lái)非常復(fù)雜,但事實(shí)上在實(shí)際項(xiàng)目的安全應(yīng)用中我們并不需要那么多功能,清楚的了解Acegi配置中各項(xiàng)的功能,有助于我們靈活的運(yùn)用Acegi于實(shí)踐中。
2.1 在Web.xml中的配置
1)? FilterToBeanProxy
Acegi通過(guò)實(shí)現(xiàn)了Filter接口的FilterToBeanProxy提供一種特殊的使用Servlet Filter的方式,它委托Spring中的Bean -- FilterChainProxy來(lái)完成過(guò)濾功能,這好處是簡(jiǎn)化了web.xml的配置,并且充分利用了Spring IOC的優(yōu)勢(shì)。FilterChainProxy包含了處理認(rèn)證過(guò)程的filter列表,每個(gè)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>
2) filter-mapping
<filter-mapping>限定了FilterToBeanProxy的URL匹配模式,只有*.do和*.jsp和/j_acegi_security_check 的請(qǐng)求才會(huì)受到權(quán)限控制,對(duì)javascript,css等不限制。
?? <filter-mapping>
????? <filter-name>Acegi Filter Chain Proxy</filter-name>
????? <url-pattern>*.do</url-pattern>
??? </filter-mapping>
???
??? <filter-mapping>
????? <filter-name>Acegi Filter Chain Proxy</filter-name>
????? <url-pattern>*.jsp</url-pattern>
??? </filter-mapping>
???
??? <filter-mapping>
????? <filter-name>Acegi Filter Chain Proxy</filter-name>
????? <url-pattern>/j_acegi_security_check</url-pattern>
</filter-mapping>
3) HttpSessionEventPublisher
<listener>的HttpSessionEventPublisher用于發(fā)布HttpSessionApplicationEvents和HttpSessionDestroyedEvent事件給spring的applicationcontext。
??? <listener>
??????? <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
??? </listener>
2.2 在applicationContext-acegi-security.xml中
2.2.1 FILTER CHAIN
FilterChainProxy會(huì)按順序來(lái)調(diào)用這些filter,使這些filter能享用Spring ioc的功能, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定義了url比較前先轉(zhuǎn)為小寫(xiě), PATTERN_TYPE_APACHE_ANT定義了使用Apache ant的匹配模式
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
??????? <property name="filterInvocationDefinitionSource">
??????????? <value>
??????????????? CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
??????????????? PATTERN_TYPE_APACHE_ANT
?????????????? /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,
basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,
exceptionTranslationFilter,filterInvocationInterceptor
??????????? </value>
??????? </property>
??? </bean>
2.2.2 基礎(chǔ)認(rèn)證
1) authenticationManager
起到認(rèn)證管理的作用,它將驗(yàn)證的功能委托給多個(gè)Provider,并通過(guò)遍歷Providers, 以保證獲取不同來(lái)源的身份認(rèn)證,若某個(gè)Provider能成功確認(rèn)當(dāng)前用戶的身份,authenticate()方法會(huì)返回一個(gè)完整的包含用戶授權(quán)信息的Authentication對(duì)象,否則會(huì)拋出一個(gè)AuthenticationException。
Acegi提供了不同的AuthenticationProvider的實(shí)現(xiàn),如:
??????? DaoAuthenticationProvider 從數(shù)據(jù)庫(kù)中讀取用戶信息驗(yàn)證身份
??????? AnonymousAuthenticationProvider 匿名用戶身份認(rèn)證
??????? RememberMeAuthenticationProvider 已存cookie中的用戶信息身份認(rèn)證
??????? AuthByAdapterProvider 使用容器的適配器驗(yàn)證身份
??????? CasAuthenticationProvider 根據(jù)Yale中心認(rèn)證服務(wù)驗(yàn)證身份, 用于實(shí)現(xiàn)單點(diǎn)登陸
??????? JaasAuthenticationProvider 從JASS登陸配置中獲取用戶信息驗(yàn)證身份
??????? RemoteAuthenticationProvider 根據(jù)遠(yuǎn)程服務(wù)驗(yàn)證用戶身份
??????? RunAsImplAuthenticationProvider 對(duì)身份已被管理器替換的用戶進(jìn)行驗(yàn)證
??????? X509AuthenticationProvider 從X509認(rèn)證中獲取用戶信息驗(yàn)證身份
??????? TestingAuthenticationProvider 單元測(cè)試時(shí)使用
??????? 每個(gè)認(rèn)證者會(huì)對(duì)自己指定的證明信息進(jìn)行認(rèn)證,如DaoAuthenticationProvider僅對(duì)UsernamePasswordAuthenticationToken這個(gè)證明信息進(jìn)行認(rèn)證。
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
??????? <property name="providers">
??????????? <list>
??????????????? <ref local="daoAuthenticationProvider"/>
??????????????? <ref local="anonymousAuthenticationProvider"/>
??????????????? <ref local="rememberMeAuthenticationProvider"/>
??????????? </list>
??????? </property>
</bean>
2) daoAuthenticationProvider
進(jìn)行簡(jiǎn)單的基于數(shù)據(jù)庫(kù)的身份驗(yàn)證。DaoAuthenticationProvider獲取數(shù)據(jù)庫(kù)中的賬號(hào)密碼并進(jìn)行匹配,若成功則在通過(guò)用戶身份的同時(shí)返回一個(gè)包含授權(quán)信息的Authentication對(duì)象,否則身份驗(yàn)證失敗,拋出一個(gè)AuthenticatiionException。
??? <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
??????? <property name="userDetailsService" ref="jdbcDaoImpl"/>
??????? <property name="userCache" ref="userCache"/>
??????? <property name="passwordEncoder" ref="passwordEncoder"/>
?? </bean>
3) passwordEncoder
使用加密器對(duì)用戶輸入的明文進(jìn)行加密。Acegi提供了三種加密器:
PlaintextPasswordEncoder—默認(rèn),不加密,返回明文.
ShaPasswordEncoder—哈希算法(SHA)加密
Md5PasswordEncoder—消息摘要(MD5)加密
<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
4) jdbcDaoImpl
用于在數(shù)據(jù)中獲取用戶信息。 acegi提供了用戶及授權(quán)的表結(jié)構(gòu),但是您也可以自己來(lái)實(shí)現(xiàn)。通過(guò)usersByUsernameQuery這個(gè)SQL得到你的(用戶ID,密碼,狀態(tài)信息);通過(guò)authoritiesByUsernameQuery這個(gè)SQL得到你的(用戶ID,授權(quán)信息)
<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
??????? <property name="dataSource" ref="dataSource"/>
??????? <property name="usersByUsernameQuery">
??????????? <value>select loginid,passwd,1 from users where loginid = ?</value>
??????? </property>
??????? <property name="authoritiesByUsernameQuery">
??????????? <value>select u.loginid,p.name from users u,roles r,permissions p,user_role ur,role_permis rp where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.permis_id and
??????????????? r.id=rp.role_id and p.status='1' and u.loginid=?</value>
??????? </property>
</bean>
5) userCache &? resourceCache
緩存用戶和資源相對(duì)應(yīng)的權(quán)限信息。每當(dāng)請(qǐng)求一個(gè)受保護(hù)資源時(shí),daoAuthenticationProvider就會(huì)被調(diào)用以獲取用戶授權(quán)信息。如果每次都從數(shù)據(jù)庫(kù)獲取的話,那代價(jià)很高,對(duì)于不常改變的用戶和資源信息來(lái)說(shuō),最好是把相關(guān)授權(quán)信息緩存起來(lái)。(詳見(jiàn) 2.6.3 資源權(quán)限定義擴(kuò)展 )
userCache提供了兩種實(shí)現(xiàn): NullUserCache和EhCacheBasedUserCache, NullUserCache實(shí)際上就是不進(jìn)行任何緩存,EhCacheBasedUserCache是使用Ehcache來(lái)實(shí)現(xiàn)緩功能。
??? <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
??????? <property name="cacheManager" ref="cacheManager"/>
??????? <property name="cacheName" value="userCache"/>
??? </bean>
??? <bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" autowire="byName">
??????? <property name="cache" ref="userCacheBackend"/>
??? </bean>
??? <bean id="resourceCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
??????? <property name="cacheManager" ref="cacheManager"/>
??????? <property name="cacheName" value="resourceCache"/>
??? </bean>
??? <bean id="resourceCache" class="org.springside.modules.security.service.acegi.cache.ResourceCache" autowire="byName">
??????? <property name="cache" ref="resourceCacheBackend"/>
??? </bean>
6) basicProcessingFilter
用于處理HTTP頭的認(rèn)證信息,如從Spring遠(yuǎn)程協(xié)議(如Hessian和Burlap)或普通的瀏覽器如IE,Navigator的HTTP頭中獲取用戶信息,將他們轉(zhuǎn)交給通過(guò)authenticationManager屬性裝配的認(rèn)證管理器。如果認(rèn)證成功,會(huì)將一個(gè)Authentication對(duì)象放到會(huì)話中,否則,如果認(rèn)證失敗,會(huì)將控制轉(zhuǎn)交給認(rèn)證入口點(diǎn)(通過(guò)authenticationEntryPoint屬性裝配)
??? <bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
??????? <property name="authenticationManager" ref="authenticationManager"/>
??????? <property name="authenticationEntryPoint" ref="basicProcessingFilterEntryPoint"/>
??? </bean>
7) basicProcessingFilterEntryPoint
通過(guò)向?yàn)g覽器發(fā)送一個(gè)HTTP401(未授權(quán))消息,提示用戶登錄。
處理基于HTTP的授權(quán)過(guò)程, 在當(dāng)驗(yàn)證過(guò)程出現(xiàn)異常后的"去向",通常實(shí)現(xiàn)轉(zhuǎn)向、在response里加入error信息等功能。
<bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
??????? <property name="realmName" value="SpringSide Realm"/>
</bean>
8) authenticationProcessingFilterEntryPoint
當(dāng)拋出AccessDeniedException時(shí),將用戶重定向到登錄界面。屬性loginFormUrl配置了一個(gè)登錄表單的URL,當(dāng)需要用戶登錄時(shí),authenticationProcessingFilterEntryPoint會(huì)將用戶重定向到該URL
<bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
??????? <property name="loginFormUrl">
??????????? <value>/security/login.jsp</value>
??????? </property>
??????? <property name="forceHttps" value="false"/>
</bean>
2.2.3 HTTP安全請(qǐng)求
1) httpSessionContextIntegrationFilter
每次request前 HttpSessionContextIntegrationFilter從Session中獲取Authentication對(duì)象,在request完后, 又把Authentication對(duì)象保存到Session中供下次request使用,此filter必須其他Acegi filter前使用,使之能跨越多個(gè)請(qǐng)求。
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"></bean>
??? <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
??????? <property name="allowIfAllAbstainDecisions" value="false"/>
??????? <property name="decisionVoters">
??????????? <list>
??????????????? <ref bean="roleVoter"/>
??????????? </list>
??????? </property>
</bean>
2) httpRequestAccessDecisionManager
經(jīng)過(guò)投票機(jī)制來(lái)決定是否可以訪問(wèn)某一資源(URL或方法)。allowIfAllAbstainDecisions為false時(shí)如果有一個(gè)或以上的decisionVoters投票通過(guò),則授權(quán)通過(guò)。可選的決策機(jī)制有ConsensusBased和UnanimousBased
??? <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
??????? <property name="allowIfAllAbstainDecisions" value="false"/>
??????? <property name="decisionVoters">
??????????? <list>
??????????????? <ref bean="roleVoter"/>
??????????? </list>
??????? </property>
??? </bean>
3) roleVoter
? 必須是以rolePrefix設(shè)定的value開(kāi)頭的權(quán)限才能進(jìn)行投票,如AUTH_ , ROLE_
??? <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
??????? <property name="rolePrefix" value="AUTH_"/>
?? </bean>
4)exceptionTranslationFilter
異常轉(zhuǎn)換過(guò)濾器,主要是處理AccessDeniedException和AuthenticationException,將給每個(gè)異常找到合適的"去向"?
?? <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
??????? <property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>
??? </bean>
5) authenticationProcessingFilter
和servlet spec差不多,處理登陸請(qǐng)求.當(dāng)身份驗(yàn)證成功時(shí),AuthenticationProcessingFilter會(huì)在會(huì)話中放置一個(gè)Authentication對(duì)象,并且重定向到登錄成功頁(yè)面
???????? authenticationFailureUrl定義登陸失敗時(shí)轉(zhuǎn)向的頁(yè)面
???????? defaultTargetUrl定義登陸成功時(shí)轉(zhuǎn)向的頁(yè)面
???????? filterProcessesUrl定義登陸請(qǐng)求的頁(yè)面
???????? rememberMeServices用于在驗(yàn)證成功后添加cookie信息
??? <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
??????? <property name="authenticationManager" ref="authenticationManager"/>
??????? <property name="authenticationFailureUrl">
??????????? <value>/security/login.jsp?login_error=1</value>
??????? </property>
??????? <property name="defaultTargetUrl">
??????????? <value>/admin/index.jsp</value>
??????? </property>
??????? <property name="filterProcessesUrl">
??????????? <value>/j_acegi_security_check</value>
??????? </property>
??????? <property name="rememberMeServices" ref="rememberMeServices"/>
??? </bean>
6) filterInvocationInterceptor
在執(zhí)行轉(zhuǎn)向url前檢查objectDefinitionSource中設(shè)定的用戶權(quán)限信息。首先,objectDefinitionSource中定義了訪問(wèn)URL需要的屬性信息(這里的屬性信息僅僅是標(biāo)志,告訴accessDecisionManager要用哪些voter來(lái)投票)。然后,authenticationManager掉用自己的provider來(lái)對(duì)用戶的認(rèn)證信息進(jìn)行校驗(yàn)。最后,有投票者根據(jù)用戶持有認(rèn)證和訪問(wèn)url需要的屬性,調(diào)用自己的voter來(lái)投票,決定是否允許訪問(wèn)。
??? <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
??????? <property name="authenticationManager" ref="authenticationManager"/>
??????? <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
??????? <property name="objectDefinitionSource" ref="filterDefinitionSource"/>
??? </bean>
7) filterDefinitionSource (詳見(jiàn) 2.6.3 資源權(quán)限定義擴(kuò)展)
自定義DBFilterInvocationDefinitionSource從數(shù)據(jù)庫(kù)和cache中讀取保護(hù)資源及其需要的訪問(wèn)權(quán)限信息?
<bean id="filterDefinitionSource" class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource">
??????? <property name="convertUrlToLowercaseBeforeComparison" value="true"/>
??????? <property name="useAntPath" value="true"/>
??????? <property name="acegiCacheManager" ref="acegiCacheManager"/>
</bean>
2.2.4 方法調(diào)用安全控制
(詳見(jiàn) 2.6.3 資源權(quán)限定義擴(kuò)展)
1) methodSecurityInterceptor
在執(zhí)行方法前進(jìn)行攔截,檢查用戶權(quán)限信息
2) methodDefinitionSource
自定義MethodDefinitionSource從cache中讀取權(quán)限
?? <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
??????? <property name="authenticationManager" ref="authenticationManager"/>
??????? <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
??????? <property name="objectDefinitionSource" ref="methodDefinitionSource"/>
??? </bean>
??? <bean id="methodDefinitionSource" class="org.springside.modules.security.service.acegi.DBMethodDefinitionSource">
??????? <property name="acegiCacheManager" ref="acegiCacheManager"/>
??? </bean>
2.3 Jcaptcha驗(yàn)證碼
采用 http://jcaptcha.sourceforge.net?作為通用的驗(yàn)證碼方案,請(qǐng)參考SpringSide中的例子,或網(wǎng)上的:
http://www.coachthrasher.com/page/blog?entry=jcaptcha_with_appfuse。
差沙在此過(guò)程中又發(fā)現(xiàn)acegi logout filter的錯(cuò)誤,進(jìn)行了修正。
另外它默認(rèn)提供的圖片比較難認(rèn),我們custom了一個(gè)美觀一點(diǎn)的版本。
大盤(pán)預(yù)測(cè) 國(guó)富論