Vincent.Chan‘s Blog

          常用鏈接

          統計

          積分與排名

          網站

          最新評論

          Acegi 資源配置動態擴展實現

          本文原出處 : http://starcraft.blogdriver.com/starcraft/1089862.html

          Acegi 資源配置動態擴展實現

          王 政 (Feiing) 于 2005-12-11

          1. 問題提出

          在使用 Acegi Security Framework 的過程中, 如果細心的話, 會發現其資源和角色配置是在配置文件中的, 下面是 Appfuse 中相關配置 :
          java代碼:?


          ? ? <bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
          ? ? ? ? <property name="authenticationManager"><ref local="authenticationManager"/></property>
          ? ? ? ? <property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>
          ? ? ? ? ?<property name="objectDefinitionSource">
          ? ? ? ? ? ? <value>
          ? ? ? ? ? ? ? ? CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
          ? ? ? ? ? ? ? ? PATTERN_TYPE_APACHE_ANT
          ? ? ? ? ? ? ? ? /signup.html=ROLE_ANONYMOUS,admin,tomcat
          ? ? ? ? ? ? ? ? /passwordhint.html*=ROLE_ANONYMOUS,admin,tomcat
          ? ? ? ? ? ? ? ? /**/*.html*=admin,tomcat
          ? ? ? ? ? ? ? ? /clickstreams.jsp=admin
          ? ? ? ? ? ? </value>
          ? ? ? ? </property>
          ? ? </bean>



          上面的配置從功能上實現了資源與角色的映射, 但用戶可能會提出在運行期動態改變權限分配的需求, 配置文件策略可能略顯不足, 下面我將提供一種基于數據庫的策略解決此問題.

          2. E-R 模型

          下圖是需要的 E-R 模型


          圖1 Acegi 標準 RBAC E-R設計

          圖中的用戶與角色不再多做解釋, 我們主要關注一下 Permission 表 和 Resource 表, 這里 Resource 表用于存儲系統資源, 在 web 層一般來說就是 url, 如果使用 acl, 就是 aclClass, 此時 Permission 表中的 aclMask 用來存儲對應的 acl 權限, 考慮到 acl 在 web 項目中使用率不高, 下面我將著重介紹 web 層的權限控制, 對 acl 有興趣的讀者可以自己參閱 Acegi Reference Guide.


          3. 如何阻止 acegi 從配置文件讀取權限配置



          從 Appfuse 中的示例性配置可以看出, acegi 對權限配置的要求是 “ 資源 = 角色1, 角色2 … 角色 n ”, 看過源代碼的讀者應該知道, 最終這些配置將被組裝為 net.sf.acegisecurity.intercept. ObjectDefinitionSource(web 層對應的實現是 net.sf.acegisecurity.intercept.web. FilterInvocationDefinitionSource), 那么我們怎么才能用數據庫的數據來組裝 FilterInvocationDefinitionSource ? 這里涉及到一個 PropertyEditor 問題, 在 Acegi 中, FilterInvocationDefinitionSource 是通過 net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSourceEditor 組裝的, 假如我們不想讓 FilterInvocationDefinitionSourceEditor 從配置文件中讀取權限配置, 就需要自己實現一個 ProdertyEditor 來覆蓋默認實現, 下面是我的 配置 :


          圖2 customerEditorConfigurer 配置

          那么, 這個 PropertyEditor 中需要做些什么呢 ? 要做的就是使用一個比較特殊的標記, 當遇到這個特殊標記的時候直接略過解析, 我這里使用的標記是 “DONT_USE_ME”, 然后在 PropertyEditor 中簡單的如下實現即可:

          java代碼:?


          /*
          * Copyright 2004-2005 wangz.
          * Project shufe_newsroom
          */

          package com.skyon.um.security.acegi.intercept.web;

          import java.beans.PropertyEditorSupport;
          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.StringReader;

          import net.sf.acegisecurity.ConfigAttributeDefinition;
          import net.sf.acegisecurity.ConfigAttributeEditor;
          import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionMap;
          import net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
          import net.sf.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap;

          import org.apache.commons.lang.StringUtils;
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;

          /**
          * @since 2005-8-4
          * @author 王政
          * @version $Id: FilterInvocationDefinitionSourceDynamicExtentionEditor.java,v 1.2 2005/11/04 15:55:07 wangzheng Exp $
          */

          publicclass FilterInvocationDefinitionSourceDynamicExtentionEditor extends
          ? ? ? ? PropertyEditorSupport{

          ? ? publicstaticfinalString ANT_PATH_KEY = "PATTERN_TYPE_APACHE_ANT";
          ? ?
          ? ? publicstaticfinalString LOWER_CASE_URL_KEY = "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON";

          ? ? publicstaticfinalString DONT_USE_ME_KEY = "DONT_USE_ME";
          ? ?
          ? ? publicstaticfinalString STAND_DELIM_CHARACTER = ",";

          ? ? privatestaticfinal Log logger = LogFactory.getLog(FilterInvocationDefinitionSourceDynamicExtentionEditor.class);
          ? ?
          ? ? /**
          ? ? ?* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
          ? ? ?*/

          ? ? publicvoid setAsText(String text)throwsIllegalArgumentException{? ? ? ? ? ? ? ?
          ? ? ? ? FilterInvocationDefinitionMap source = new RegExpBasedFilterInvocationDefinitionMap();
          ? ? ? ? ? ? ? ?
          ? ? ? ? if(StringUtils.isBlank(text)){
          ? ? ? ? ? ? // Leave target object empty
          ? ? ? ? }else{? ? ? ? ?
          ? ? ? ? ? ? // Check if we need to override the default definition map
          ? ? ? ? ? ? if(text.lastIndexOf(ANT_PATH_KEY) != -1){
          ? ? ? ? ? ? ? ? source = new PathBasedFilterInvocationDefinitionMap();

          ? ? ? ? ? ? ? ? if(logger.isDebugEnabled()){
          ? ? ? ? ? ? ? ? ? ? logger.debug(("Detected PATTERN_TYPE_APACHE_ANT directive; using Apache Ant style path expressions"));
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }

          ? ? ? ? ? ? if(text.lastIndexOf(LOWER_CASE_URL_KEY) != -1){
          ? ? ? ? ? ? ? ? if(logger.isDebugEnabled()){
          ? ? ? ? ? ? ? ? ? ? logger.debug("Instructing mapper to convert URLs to lowercase before comparison");
          ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? source.setConvertUrlToLowercaseBeforeComparison(true);
          ? ? ? ? ? ? }
          ? ? ? ? ? ?
          ? ? ? ? ? ? if(text.indexOf(DONT_USE_ME_KEY) != -1){
          ? ? ? ? ? ? ? ? if(logger.isDebugEnabled()){
          ? ? ? ? ? ? ? ? ? ? logger.debug("DETECTED " + DONT_USE_ME_KEY + " directive;? skip parse, Use " + EhCacheBasedFilterInvocationDefinitionSourceCache.class + " to parse!");
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ? addSecureUrl(source, "/dontuseme", "dontuseme");
          ? ? ? ? ? ? }else{
          ? ? ? ? ? ? ? ? BufferedReader br = newBufferedReader(newStringReader(text));
          ? ? ? ? ? ? ? ? int counter = 0;
          ? ? ? ? ? ? ? ? String line;

          ? ? ? ? ? ? ? ? while(true){
          ? ? ? ? ? ? ? ? ? ? counter++;

          ? ? ? ? ? ? ? ? ? ? try{
          ? ? ? ? ? ? ? ? ? ? ? ? line = br.readLine();
          ? ? ? ? ? ? ? ? ? ? }catch(IOException ioe){
          ? ? ? ? ? ? ? ? ? ? ? ? throw newIllegalArgumentException(ioe.getMessage());
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? if(line == null){
          ? ? ? ? ? ? ? ? ? ? ? ? break;
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? line = line.trim();

          ? ? ? ? ? ? ? ? ? ? if(logger.isDebugEnabled()){
          ? ? ? ? ? ? ? ? ? ? ? ? logger.debug("Line " + counter + ": " + line);
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? if(line.startsWith("//")) {
          ? ? ? ? ? ? ? ? ? ? ? ? continue;
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? if(line.equals(LOWER_CASE_URL_KEY)){
          ? ? ? ? ? ? ? ? ? ? ? ? continue;
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? if(line.lastIndexOf('=') == -1){
          ? ? ? ? ? ? ? ? ? ? ? ? continue;
          ? ? ? ? ? ? ? ? ? ? }

          ? ? ? ? ? ? ? ? ? ? // Tokenize the line into its name/value tokens
          ? ? ? ? ? ? ? ? ? ? String[] nameValue = org.springframework.util.StringUtils.delimitedListToStringArray(line, "=");
          ? ? ? ? ? ? ? ? ? ? String name = nameValue[0];
          ? ? ? ? ? ? ? ? ? ? String value = nameValue[1];

          ? ? ? ? ? ? ? ? ? ? addSecureUrl(source, name, value);? ? ? ? ? ? ? ?
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }
          ? ? ? ? ? ?


          ? ? ? ? }

          ? ? ? ? setValue(source);
          ? ? }
          ? ?

          ? ? /**
          ? ? ?* @param source
          ? ? ?* @param name
          ? ? ?* @param value
          ? ? ?* @throws IllegalArgumentException
          ? ? ?*/

          ? ? privatevoid addSecureUrl(FilterInvocationDefinitionMap source, String name, String value)
          ? ? ? ? throwsIllegalArgumentException{
          ? ? ? ?
          ? ? ? ? // Convert value to series of security configuration attributes
          ? ? ? ? ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
          ? ? ? ? configAttribEd.setAsText(value);

          ? ? ? ? ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();

          ? ? ? ? // Register the regular expression and its attribute
          ? ? ? ? source.addSecureUrl(name, attr);
          ? ? }


          }




          Ok, 現在 FilterInvocationDefinitionSourceDynamicExtentionEditor 遇到配置文件中的 “DONT_USE_ME” 時將直接略過, 下面是我的 filterInvocationInterceptor 配置:

          圖3 filterInvocationInterceptor 配置

          現在, 我們已經成功阻止 acegi 從配置文件讀取權限配置, 下一個問題就是:


          4. 如何從表中數據組裝 FilterInvocationDefinitionSource



          為了實現此功能, 需要一個自定義的資源定義接口來提供 FilterInvocationDefinitionSource, 此接口可能會是這樣 :
          java代碼:?


          /*
          * Copyright 2005-2010 the original author or autors
          *?
          *? ? http://www.skyon.com.cn
          *
          * Project { SkyonFramwork }
          */

          package com.skyon.um.security.acegi.intercept.web;

          import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource;

          import org.springframework.beans.factory.FactoryBean;

          import com.skyon.framework.spring.ehcache.FlushableCache;

          /**
          * <class>FilterInvocationDefinitionSourceCache</class> use to hold the global FilterInvocationDefinitionSource,
          * it keeps a static variable , if the source been changed(generally the database data),? the reload method should be called
          *
          * @see com.skyon.um.security.acegi.intercept.event.FilterInvocationDefinitionSourceChangedEvent
          * @see com.skyon.um.security.acegi.intercept.event.FilterInvocationDefinitionSourceListener
          * @see com.skyon.um.security.acegi.intercept.web.SecurityEnforcementDynamicExtensionFilter
          * @since 2005-8-7
          * @author 王政
          * @version $Id: FilterInvocationDefinitionSourceCache.java,v 1.1 2005/11/04 15:55:07 wangzheng Exp $
          */

          publicinterface FilterInvocationDefinitionSourceCache extends FactoryBean, FlushableCache {
          ? ? ? ?
          ? ? ? ? /** The Perl5 expression? */
          ? ? int REOURCE_EXPRESSION_PERL5_REG_EXP = 1;
          ? ?
          ? ? /** The ant path expression */
          ? ? int RESOURCE_EXPRESSION_ANT_PATH_KEY = 2;
          ? ?
          ? ? /**
          ? ? ?* Set resource expression, the value must be {@link #REOURCE_EXPRESSION_PERL5_REG_EXP} or {@link #RESOURCE_EXPRESSION_ANT_PATH_KEY}
          ? ? ?* @see #REOURCE_EXPRESSION_PERL5_REG_EXP
          ? ? ?* @see #RESOURCE_EXPRESSION_ANT_PATH_KEY
          ? ? ?* @param resourceExpression the resource expression
          ? ? ?*/

          ? ? void setResourceExpression(int resourceExpression);
          ? ?
          ? ? /**
          ? ? ?* Set whether convert url to lowercase before comparison
          ? ? ?* @param convertUrlToLowercaseBeforeComparison whether convertUrlToLowercaseBeforeComparison
          ? ? ?*/

          ? ? void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison);
          ? ?
          ? ? ? ? /**
          ? ? ? ? * Get the defination source, generally from a database schema
          ? ? ? ? * @return the defination source
          ? ? ? ? */

          ? ? FilterInvocationDefinitionSource getFilterInvocationDefinitionSource();
          ? ? ? ? ? ?

          }



          其核心方法是 FilterInvocationDefinitionSource getFilterInvocationDefinitionSource(), 此方法將代替配置文件提供資源和角色的配置, 下面是實現

          java代碼:?


          /*
          * Copyright 2005-2010 the original author or autors
          *?
          *? ? http://www.skyon.com.cn
          *
          * Project { SkyonFramwork }
          */

          package com.skyon.um.security.acegi.intercept.web;

          import net.sf.acegisecurity.ConfigAttributeDefinition;
          import net.sf.acegisecurity.ConfigAttributeEditor;
          import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionMap;
          import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
          import net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
          import net.sf.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap;
          import net.sf.ehcache.Cache;
          import net.sf.ehcache.Element;

          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          import org.springframework.beans.factory.InitializingBean;
          import org.springframework.util.Assert;

          import com.skyon.framework.spring.ehcache.CacheUtils;
          import com.skyon.framework.spring.ehcache.SerializableObjectProvider;
          import com.skyon.framework.spring.support.MandatorySingletonBeanSupport;

          /**
          * @since 2005-8-7
          * @author 王政
          * @version $Id: EhCacheBasedFilterInvocationDefinitionSourceCache.java,v 1.2 2005/11/17 09:38:25 wangzheng Exp $
          */

          publicclass EhCacheBasedFilterInvocationDefinitionSourceCache extends MandatorySingletonBeanSupport
          ? ? ? ? implements FilterInvocationDefinitionSourceCache, InitializingBean {
          ? ?
          ? ? privatestaticfinal Log logger = LogFactory.getLog(EhCacheBasedFilterInvocationDefinitionSourceCache.class);
          ? ?
          ? ? privateint resourceExpression;
          ? ?
          ? ? privateboolean convertUrlToLowercaseBeforeComparison = false;
          ? ? ? ?
          ? ? private ResourceMappingProvider resourceMappingProvider;
          ? ?
          ? ? private Cache cache;
          ? ?
          ? ? privateObject lock = newObject();
          ? ?
          ? ? /**
          ? ? ?* @see com.skyon.um.security.acegi.intercept.web.FilterInvocationDefinitionSourceCache#getFilterInvocationDefinitionSource()
          ? ? ?*/

          ? ? public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource(){
          ? ? ? ? ? ? synchronized (lock){
          ? ? ? ? ? ? ? ? Element element = CacheUtils.get(getCache(), "key");
          ? ? ? ? ? ? ? ?
          ? ? ? ? ? ? ? ? if(element == null){
          ? ? ? ? ? ? ? ? ? ? ? ? FilterInvocationDefinitionSource definitionSource = (FilterInvocationDefinitionSource) getFilterInvocationDefinitionSourceFromBackend();
          ? ? ? ? ? ? ? ? ? ? ? ? element = newElement("key", new SerializableObjectProvider(definitionSource));
          ? ? ? ? ? ? ? ? ? ? ? ? getCache().put(element);
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ?
          ? ? ? ? ? ? ? ? return(FilterInvocationDefinitionSource)((SerializableObjectProvider) element.getValue()).getSourceObject();
          ? ? ? ? ? ? }
          ? ? }
          ? ? ? ? ? ?
          ? ? ? ? publicvoid flushCache(){
          ? ? ? ? ? ? ? ? CacheUtils.flushCache(getCache());
          ? ? ? ? ? ? ? ? getFilterInvocationDefinitionSource();
          ? ? ? ? }
          ? ?
          ? ? private FilterInvocationDefinitionMap getFilterInvocationDefinitionSourceFromBackend(){? ? ? ?
          ? ? ? ? ? ? logger.info(" 開始加載系統資源權限數據到緩存... ");
          ? ? ? ? ? ?
          ? ? ? ? ? ? FilterInvocationDefinitionMap definitionSource = null;
          ? ? ? ?
          ? ? ? ? ? ? switch(resourceExpression){
          ? ? ? ? ? ? case REOURCE_EXPRESSION_PERL5_REG_EXP : {
          ? ? ? ? ? ? ? ? definitionSource = new RegExpBasedFilterInvocationDefinitionMap();
          ? ? ? ? ? ? ? ? break;
          ? ? ? ? ? ? }
          ? ? ? ? ? ? case RESOURCE_EXPRESSION_ANT_PATH_KEY : {
          ? ? ? ? ? ? ? ? definitionSource = new PathBasedFilterInvocationDefinitionMap();
          ? ? ? ? ? ? ? ? break;
          ? ? ? ? ? ? }
          ? ? ? ? ? ? default : {
          ? ? ? ? ? ? ? ? throwException();
          ? ? ? ? ? ? }
          ? ? ? ? }
          ? ? ? ?
          ? ? ? ? definitionSource.setConvertUrlToLowercaseBeforeComparison(isConvertUrlToLowercaseBeforeComparison());
          ? ? ? ?
          ? ? ? ? ResourceMapping[] mappings = getResourceMappingProvider().getResourceMappings();
          ? ? ? ? if(mappings == null || mappings.length ==0){
          ? ? ? ? ? ? return definitionSource;
          ? ? ? ? }
          ? ? ? ?
          ? ? ? ? for(int i = 0; i < mappings.length; i++){
          ? ? ? ? ? ? ResourceMapping mapping = mappings[i];
          ? ? ? ? ? ? String[] recipents = mapping.getRecipients();
          ? ? ? ? ? ?
          ? ? ? ? ? ? if(recipents == null || recipents.length == 0){
          ? ? ? ? ? ? ? ? if(logger.isErrorEnabled()){
          ? ? ? ? ? ? ? ? ? ? logger.error("Notice, the resource : " + mapping.getResourcePath() + " hasn't no recipents, it will access by any one ! ");
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ? continue;
          ? ? ? ? ? ? }
          ? ? ? ? ? ?
          ? ? ? ? ? ? StringBuffer valueBuffer = new StringBuffer();
          ? ? ? ? ? ? for (int j = 0; j < recipents.length; j++) {
          ? ? ? ? ? ? ? ? valueBuffer.append(recipents[j]);
          ? ? ? ? ? ? ? ? if (j < recipents.length - 1) {
          ? ? ? ? ? ? ? ? ? ? valueBuffer.append(FilterInvocationDefinitionSourceDynamicExtentionEditor.STAND_DELIM_CHARACTER);
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }
          ? ? ? ? ? ? String value = valueBuffer.toString();? ? ? ? ? ? ? ? ? ?
          ? ? ? ? ? ? addSecureUrl(definitionSource, mapping.getResourcePath(), value);
          ? ? ? ? ?}
          ? ? ? ?
          ? ? ? ? logger.info(" 成功加載系統資源權限數據到緩存 ! ");
          ? ? ? ? return definitionSource;
          ? ? }

          ? ? /**
          ? ? ?* @param source
          ? ? ?* @param name
          ? ? ?* @param value
          ? ? ?* @throws IllegalArgumentException
          ? ? ?*/
          ? ? private synchronized void addSecureUrl(FilterInvocationDefinitionMap source, String name, String value)
          ? ? ? ? throws IllegalArgumentException {
          ? ? ? ?
          ? ? ? ? // Convert value to series of security configuration attributes
          ? ? ? ? ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
          ? ? ? ? configAttribEd.setAsText(value);

          ? ? ? ? ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();

          ? ? ? ? // Register the regular expression and its attribute
          ? ? ? ? source.addSecureUrl(name, attr);
          ? ? }
          ? ?

          ? ? public void afterPropertiesSet() throws Exception {
          ? ? ? ? if (resourceExpression != REOURCE_EXPRESSION_PERL5_REG_EXP && resourceExpression != RESOURCE_EXPRESSION_ANT_PATH_KEY) {
          ? ? ? ? ? ? throwException();
          ? ? ? ? }? ? ? ?
          ? ? ? ? Assert.notNull(getResourceMappingProvider(), " resourceMappingProvider must be specified");? ? ?
          ? ? ? ? Assert.notNull(getCache(), " cache must be specified");? ?
          ? ? }


          ? ? /**
          ? ? ?* @throws IllegalArgumentException
          ? ? ?*/
          ? ? private void throwException() throws IllegalArgumentException {
          ? ? ? ? throw new IllegalArgumentException("wrong resourceExpression value");
          ? ? }
          ? ? ? ?
          ? ? /**
          ? ? ?* @return Returns the resourceMappingProvider.
          ? ? ?*/
          ? ? public ResourceMappingProvider getResourceMappingProvider() {
          ? ? ? ? return resourceMappingProvider;
          ? ? }

          ? ? /**
          ? ? ?* @param resourceMappingProvider The resourceMappingProvider to set.
          ? ? ?*/
          ? ? public void setResourceMappingProvider(ResourceMappingProvider resourceMappingProvider) {
          ? ? ? ? this.resourceMappingProvider = resourceMappingProvider;
          ? ? }

          ? ? /**
          ? ? ?* @return Returns the convertUrlToLowercaseBeforeComparison.
          ? ? ?*/
          ? ? public boolean isConvertUrlToLowercaseBeforeComparison() {
          ? ? ? ? return convertUrlToLowercaseBeforeComparison;
          ? ? }

          ? ? /**
          ? ? ?* @param convertUrlToLowercaseBeforeComparison The convertUrlToLowercaseBeforeComparison to set.
          ? ? ?*/
          ? ? public void setConvertUrlToLowercaseBeforeComparison(
          ? ? ? ? ? ? boolean convertUrlToLowercaseBeforeComparison) {
          ? ? ? ? this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
          ? ? }

          ? ? /**
          ? ? ?* @return Returns the resourceExpression.
          ? ? ?*/
          ? ? public int getResourceExpression() {
          ? ? ? ? return resourceExpression;
          ? ? }

          ? ? /**
          ? ? ?* @param resourceExpression The resourceExpression to set.
          ? ? ?*/
          ? ? public void setResourceExpression(int resourceExpression) {
          ? ? ? ? this.resourceExpression = resourceExpression;
          ? ? }


          ? ? ? ? /**
          ? ? ? ? * @return Returns the cache.
          ? ? ? ? */
          ? ? ? ? public Cache getCache() {
          ? ? ? ? ? ? ? ? return cache;
          ? ? ? ? }


          ? ? ? ? /**
          ? ? ? ? * @param cache The cache to set.
          ? ? ? ? */
          ? ? ? ? public void setCache(Cache cache) {
          ? ? ? ? ? ? ? ? this.cache = cache;
          ? ? ? ? }



          ? ? ? ?
          }



          實現采用 EhCache 緩存資源權限配置, 這樣如果資源權限數據發生變化, 可以 flush Cache 從數據庫重新讀取. 至于代碼中的 ResourceMapingProvider 實現, 簡單的把 Resource 表和 Role 表中的數據讀取過來即可, 這里不再贅述.



          5. 如何將數據庫中的權限配置傳遞給 FilterInvocationInterceptor


          完成以上步驟后, 最后一步就是如何把 FilterInvocationDefinitionSourceCache 中的 FilterInvocationDefinitionSource 傳遞給 FilterInvocationInterceptor, Simple implemention :

          java代碼:?


          public class SecurityEnforcementDynamicExtensionFilter extends
          ? ? ? ? SecurityEnforcementFilter implements InitializingBean {
          … 略去

          publicvoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throwsIOException, ServletException {? ? ? ? ? ? ? ?? ? ? ?
          ? ? ? ? ? ? ? ? // get the defination source form soure holder
          ? ? ? ? ? ? ? ? getFilterSecurityInterceptor().setObjectDefinitionSource(getDefinitionSourceCache().getFilterInvocationDefinitionSource());
          }
          }



          配置:


          It’s Over Now.

          posted on 2006-04-28 23:41 Vincent.Chen 閱讀(233) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 芦山县| 盘山县| 葫芦岛市| 濉溪县| 乾安县| 汝城县| 保德县| 临沧市| 安庆市| 雷山县| 荔波县| 毕节市| 周宁县| 西乌| 蛟河市| 禹城市| 大姚县| 图们市| 乳山市| 遂昌县| 东山县| 正蓝旗| 酉阳| 巴青县| 宜春市| 天镇县| 新邵县| 虎林市| 富蕴县| 张家界市| 梨树县| 内江市| 新巴尔虎右旗| 永仁县| 杭锦旗| 聂荣县| 乌拉特后旗| 大兴区| 太和县| 孟州市| 桂林市|