Acegi 的配置看起來非常復雜
但事實上在實際項目的安全應用中我們並不需要那麼多功能
清楚的了解Acegi配置中各項的功能
有助於我們靈活的運用Acegi於實踐中
在Webxml中的配置
) FilterToBeanProxy
Acegi通過實現了Filter接口的FilterToBeanProxy提供一種特殊的使用Servlet Filter的方式它委托Spring中的Bean FilterChainProxy來完成過濾功能這好處是簡化了webxml的配置並且充分利用了Spring IOC的優勢FilterChainProxy包含了處理認證過程的filter列表每個filter都有各自的功能
<filter>
<filtername>Acegi Filter Chain Proxy</filtername>
<filterclass>orgacegisecurityutilFilterToBeanProxy</filterclass>
<initparam>
<paramname>targetClass</paramname>
<paramvalue>orgacegisecurityutilFilterChainProxy</paramvalue>
</initparam>
</filter>
) filtermapping
<filtermapping>限定了FilterToBeanProxy的URL匹配模式只有*do和*jsp和/j_acegi_security_check 的請求才會受到權限控制對javascriptcss等不限制
<filtermapping>
<filtername>Acegi Filter Chain Proxy</filtername>
<urlpattern>*do</urlpattern>
</filtermapping>
<filtermapping>
<filtername>Acegi Filter Chain Proxy</filtername>
<urlpattern>*jsp</urlpattern>
</filtermapping>
<filtermapping>
<filtername>Acegi Filter Chain Proxy</filtername>
<urlpattern>/j_acegi_security_check</urlpattern>
</filtermapping>
) HttpSessionEventPublisher
<listener>的HttpSessionEventPublisher用於發布HttpSessionApplicationEvents和HttpSessionDestroyedEvent事件給spring的applicationcontext
<listener>
<listenerclass>orgacegisecurityuisessionHttpSessionEventPublisher</listenerclass>
</listener>
在applicationContextacegisecurityxml中
FILTER CHAIN
FilterChainProxy會按順序來調用這些filter使這些filter能享用Spring ioc的功能 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定義了url比較前先轉為小寫 PATTERN_TYPE_APACHE_ANT定義了使用Apache ant的匹配模式
<bean id=filterChainProxy class=orgacegisecurityutilFilterChainProxy>
<property name=filterInvocationDefinitionSource>
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilterauthenticationProcessingFilter
basicProcessingFilterrememberMeProcessingFilteranonymousProcessingFilter
exceptionTranslationFilterfilterInvocationInterceptor
</value>
</property>
</bean>
基礎認證
) authenticationManager
起到認證管理的作用它將驗證的功能委托給多個Provider並通過遍歷Providers 以保證獲取不同來源的身份認證若某個Provider能成功確認當前用戶的身份authenticate()方法會返回一個完整的包含用戶授權信息的Authentication對象否則會拋出一個AuthenticationException
Acegi提供了不同的AuthenticationProvider的實現如
DaoAuthenticationProvider 從數據庫中讀取用戶信息驗證身份
AnonymousAuthenticationProvider 匿名用戶身份認證
RememberMeAuthenticationProvider 已存cookie中的用戶信息身份認證
AuthByAdapterProvider 使用容器的適配器驗證身份
CasAuthenticationProvider 根據Yale中心認證服務驗證身份 用於實現單點登陸
JaasAuthenticationProvider 從JASS登陸配置中獲取用戶信息驗證身份
RemoteAuthenticationProvider 根據遠程服務驗證用戶身份
RunAsImplAuthenticationProvider 對身份已被管理器替換的用戶進行驗證
XAuthenticationProvider 從X認證中獲取用戶信息驗證身份
TestingAuthenticationProvider 單元測試時使用
每個認證者會對自己指定的證明信息進行認證如DaoAuthenticationProvider僅對UsernamePasswordAuthenticationToken這個證明信息進行認證
<bean id=authenticationManager class=orgacegisecurityprovidersProviderManager>
<property name=providers>
<list>
<ref local=daoAuthenticationProvider/>
<ref local=anonymousAuthenticationProvider/>
<ref local=rememberMeAuthenticationProvider/>
</list>
</property>
</bean>
) daoAuthenticationProvider
進行簡單的基於數據庫的身份驗證DaoAuthenticationProvider獲取數據庫中的賬號密碼並進行匹配若成功則在通過用戶身份的同時返回一個包含授權信息的Authentication對象否則身份驗證失敗拋出一個AuthenticatiionException
<bean id=daoAuthenticationProvider
class=orgacegisecurityprovidersdaoDaoAuthenticationProvider>
<property name=userDetailsService ref=jdbcDaoImpl/>
<property name=userCache ref=userCache/>
<property name=passwordEncoder ref=passwordEncoder/>
</bean>
) passwordEncoder
使用加密器對用戶輸入的明文進行加密Acegi提供了三種加密器:
PlaintextPasswordEncoder—默認不加密返回明文
ShaPasswordEncoder—哈希算法(SHA)加密
MdPasswordEncoder—消息摘要(MD)加密
<bean id=passwordEncoder class=orgacegisecurityprovidersencodingMdPasswordEncoder/>
) jdbcDaoImpl
用於在數據中獲取用戶信息 acegi提供了用戶及授權的表結構但是您也可以自己來實現通過usersByUsernameQuery這個SQL得到你的(用戶ID密碼狀態信息);通過authoritiesByUsernameQuery這個SQL得到你的(用戶ID授權信息)
<bean id=jdbcDaoImpl
class=orgacegisecurityuserdetailsjdbcJdbcDaoImpl>
<property name=dataSource
ref=dataSource/>
<property
name=usersByUsernameQuery>
<value>select loginidpasswd from users where loginid =
?</value>
</property>
<property
name=authoritiesByUsernameQuery>
<value>select uloginidpname from users uroles rpermissions
puser_role urrole_permis rp where uid=uruser_id and rid=urrole_id and
pid=rppermis_id
and
rid=rprole_id and pstatus= and
uloginid=?</value>
</property>
</bean>
) userCache & resourceCache
緩存用戶和資源相對應的權限信息每當請求一個受保護資源時daoAuthenticationProvider就會被調用以獲取用戶授權信息如果每次都從數據庫獲取的話那代價很高對於不常改變的用戶和資源信息來說最好是把相關授權信息緩存起來(詳見 資源權限定義擴展 )
userCache提供了兩種實現: NullUserCache和EhCacheBasedUserCache NullUserCache實際上就是不進行任何緩存EhCacheBasedUserCache是使用Ehcache來實現緩功能
<bean id=userCacheBackend
class=orgspringframeworkcacheehcacheEhCacheFactoryBean>
<property name=cacheManager
ref=cacheManager/>
<property name=cacheName value=userCache/>
</bean>
<bean id=userCache
class=orgacegisecurityprovidersdaocacheEhCacheBasedUserCache
autowire=byName>
<property
name=cache ref=userCacheBackend/>
</bean>
<bean id=resourceCacheBackend
class=orgspringframeworkcacheehcacheEhCacheFactoryBean>
<property name=cacheManager
ref=cacheManager/>
<property name=cacheName value=resourceCache/>
</bean>
<bean id=resourceCache
class=orgspringsidemodulessecurityserviceacegicacheResourceCache
autowire=byName>
<property
name=cache ref=resourceCacheBackend/>
</bean>
) basicProcessingFilter
用於處理HTTP頭的認證信息如從Spring遠程協議(如Hessian和Burlap)或普通的浏覽器如IENavigator的HTTP頭中獲取用戶信息將他們轉交給通過authenticationManager屬性裝配的認證管理器如果認證成功會將一個Authentication對象放到會話中否則如果認證失敗會將控制轉交給認證入口點(通過authenticationEntryPoint屬性裝配)
<bean id=basicProcessingFilter
class=orgacegisecurityuibasicauthBasicProcessingFilter>
<property name=authenticationManager ref=authenticationManager/>
<property name=authenticationEntryPoint ref=basicProcessingFilterEntryPoint/>
</bean>
) basicProcessingFilterEntryPoint
通過向浏覽器發送一個HTTP(未授權)消息提示用戶登錄
處理基於HTTP的授權過程 在當驗證過程出現異常後的去向通常實現轉向在response裡加入error信息等功能
<bean
id=basicProcessingFilterEntryPoint
class=orgacegisecurityuibasicauthBasicProcessingFilterEntryPoint>
<property name=realmName value=SpringSide Realm/>
</bean>
) authenticationProcessingFilterEntryPoint
當拋出AccessDeniedException時將用戶重定向到登錄界面屬性loginFormUrl配置了一個登錄表單的URL當需要用戶登錄時authenticationProcessingFilterEntryPoint會將用戶重定向到該URL
<bean id=authenticationProcessingFilterEntryPoint
class=orgacegisecurityuiwebappAuthenticationProcessingFilterEntryPoint>
<property
name=loginFormUrl>
<value>/security/loginjsp</value>
</property>
<property
name=forceHttps value=false/>
</bean>
HTTP安全請求
) httpSessionContextIntegrationFilter
每次request前 HttpSessionContextIntegrationFilter從Session中獲取Authentication對象在request完後 又把Authentication對象保存到Session中供下次request使用此filter必須其他Acegi filter前使用使之能跨越多個請求
<bean id=httpSessionContextIntegrationFilter
class=ontextHttpSessionContextIntegrationFilter></bean>
<bean id=httpRequestAccessDecisionManager
class=orgacegisecurityvoteAffirmativeBased>
<property name=allowIfAllAbstainDecisions value=false/>
<property name=decisionVoters>
<list>
<ref bean=roleVoter/>
</list>
</property>
</bean>
) httpRequestAccessDecisionManager
經過投票機制來決定是否可以訪問某一資源(URL或方法)allowIfAllAbstainDecisions為false時如果有一個或以上的decisionVoters投票通過則授權通過可選的決策機制有ConsensusBased和UnanimousBased
<bean id=httpRequestAccessDecisionManager
class=orgacegisecurityvoteAffirmativeBased>
<property name=allowIfAllAbstainDecisions value=false/>
<property name=decisionVoters>
<list>
<ref bean=roleVoter/>
</list>
</property>
</bean>
) roleVoter
必須是以rolePrefix設定的value開頭的權限才能進行投票如AUTH_ ROLE_
<bean id=roleVoter class=orgacegisecurityvoteRoleVoter>
<property name=rolePrefix value=AUTH_/>
</bean>
)exceptionTranslationFilter
異常轉換過濾器主要是處理AccessDeniedException和AuthenticationException將給每個異常找到合適的去向
<bean id=exceptionTranslationFilter
class=orgacegisecurityuiExceptionTranslationFilter>
<property name=authenticationEntryPoint
ref=authenticationProcessingFilterEntryPoint/>
</bean>
) authenticationProcessingFilter
和servlet spec差不多處理登陸請求當身份驗證成功時AuthenticationProcessingFilter會在會話中放置一個Authentication對象並且重定向到登錄成功頁面
authenticationFailureUrl定義登陸失敗時轉向的頁面
defaultTargetUrl定義登陸成功時轉向的頁面
filterProcessesUrl定義登陸請求的頁面
rememberMeServices用於在驗證成功後添加cookie信息
<bean id=authenticationProcessingFilter
class=orgacegisecurityuiwebappAuthenticationProcessingFilter>
<property name=authenticationManager ref=authenticationManager/>
<property name=authenticationFailureUrl>
<value>/security/loginjsp?login_error=</value>
</property>
<property name=defaultTargetUrl>
<value>/admin/indexjsp</value>
</property>
<property name=filterProcessesUrl>
<value>/j_acegi_security_check</value>
</property>
<property name=rememberMeServices ref=rememberMeServices/>
</bean>
) filterInvocationInterceptor
在執行轉向url前檢查objectDefinitionSource中設定的用戶權限信息首先objectDefinitionSource中定義了訪問URL需要的屬性信息(這裡的屬性信息僅僅是標志告訴accessDecisionManager要用哪些voter來投票)然後authenticationManager掉用自己的provider來對用戶的認證信息進行校驗最後有投票者根據用戶持有認證和訪問url需要的屬性調用自己的voter來投票決定是否允許訪問
<bean id=filterInvocationInterceptor
class=orgacegisecurityinterceptwebFilterSecurityInterceptor>
<property name=authenticationManager ref=authenticationManager/>
<property name=accessDecisionManager ref=httpRequestAccessDecisionManager/>
<property name=objectDefinitionSource ref=filterDefinitionSource/>
</bean>
) filterDefinitionSource (詳見 資源權限定義擴展)
自定義DBFilterInvocationDefinitionSource從數據庫和cache中讀取保護資源及其需要的訪問權限信息
<bean id=filterDefinitionSource
class=orgspringsidemodulessecurityserviceacegiDBFilterInvocationDefinitionSource>
<property name=convertUrlToLowercaseBeforeComparison value=true/>
<property name=useAntPath value=true/>
<property name=acegiCacheManager ref=acegiCacheManager/>
</bean>
方法調用安全控制
(詳見 資源權限定義擴展)
) methodSecurityInterceptor
在執行方法前進行攔截檢查用戶權限信息
) methodDefinitionSource
自定義MethodDefinitionSource從cache中讀取權限
<bean id=methodSecurityInterceptor
class=orgacegisethodaopallianceMethodSecurityInterceptor>
<property name=authenticationManager ref=authenticationManager/>
<property name=accessDecisionManager ref=httpRequestAccessDecisionManager/>
<property name=objectDefinitionSource ref=methodDefinitionSource/>
</bean>
<bean id=methodDefinitionSource
class=orgspringsidemodulessecurityserviceacegiDBMethodDefinitionSource>
<property name=acegiCacheManager ref=acegiCacheManager/>
</bean>
Jcaptcha驗證碼
采用 ;作為通用的驗證碼方案請參考SpringSide中的例子或網上的
_with_appfuse
差沙在此過程中又發現acegi logout filter的錯誤進行了修正
另外它默認提供的圖片比較難認我們custom了一個美觀一點的版本
From:http://tw.wingwit.com/Article/program/net/201311/13798.html