本站首页    管理页面    写新日志    退出


«December 2025»
123456
78910111213
14151617181920
21222324252627
28293031


公告
本博客在此声明所有文章均为转摘,只做资料收集使用。并无其他商业用途。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:210
评论数量:205
留言数量:-19
访问次数:929155
建立时间:2007年5月10日




[acegi权限认证]Acegi 动态权限存储策略
文章收藏,  网上资源,  软件技术,  电脑与网络

李小白 发表于 2007/7/12 14:53:36

 载自:http://publishblog.blogdriver.com/blog/tb.b?diaryID=1135045 作者: Feiing 2006年02月18日, 星期六 00:11   在我之前的一篇文章里, 说明了在 Acegi 中如何将资源权限数据存储到数据库中, 文章见 http://www.hibernate.org.cn/viewtopic.php?t=17538, 虽然文中方式实现了从数据库读取资源权限, 但是代码量较大, 并且重载了 SecurityEnforcementFilter, 造成比较大的侵入性, 这里我将提供另一种更简洁的方式实现此功能. 入口还是 org.acegisecurity.intercept.web.FilterSecurityInterceptor, 资源权限配置来自于 objectDefinitionSource, 标准配置方式采用 FilterInvocationDefinitionSourceEditor 解析, 支持 Perl5 和 AntPath 两种风格, 为了实现从其它位置(典型如数据库), 我们要做的就是实现一个自定义的 FilterInvocationDefinitionSource, 查看类层次结构图后可以发现, acegi 中已经有一个 AbstractFilterInvocationDefinitionSource 已经实现此接口, 只要实现一个抽象方法即可  public abstract ConfigAttributeDefinition lookupAttributes(String url); 因此, 自定义一个 Class 如下 : public class RdbmsBasedFilterInvocationDefinitionSource extends AbstractFilterInvocationDefinitionSource 因为 acegi 中已经提供了 Perl5 和 AntPath 的实现, 只需要集成过来即可, 因此定义接口如下 /** * <class>ConfigableFilterInvocationDefinition</class> 支持 Perl5 和 ant Path 两种风格的资源配置方式 * @since 2006-1-19 * @author 王政 * @version $Id: ConfigableFilterInvocationDefinition.java,v 1.3 2006/01/19 09:40:37 wz Exp $ */public interface ConfigableFilterInvocationDefinition {  /** The Perl5 expression  */ String PERL5_KEY = "PATTERN_TYPE_PERL5";        /** The ant path expression */    String ANT_PATH_KEY = "PATTERN_TYPE_APACHE_ANT";     /** 标准分隔符 */    String STAND_DELIM_CHARACTER = ",";        /**     * Set resource expression, the value must be {@link #PERL5_KEY_REG_EXP} or {@link #ANT_PATH_KEY}     * @see #REOURCE_EXPRESSION_PERL5_REG_EXP     * @see #RESOURCE_EXPRESSION_ANT_PATH_KEY     * @param resourceExpression the resource expression     */    void setResourceExpression(String resourceExpression);        /**     *      * @return resource expression     */    String getResourceExpression();        /**     * Set whether convert url to lowercase before comparison     * @param convertUrlToLowercaseBeforeComparison whether convertUrlToLowercaseBeforeComparison     */    void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison);     /**     *      * @return whether convert url to lowercase before comparison     */    boolean isConvertUrlToLowercaseBeforeComparison();   }  再让 RdbmsBasedFilterInvocationDefinitionSource 实现此接口即可, 下面是简略代码  /** * <class>RdbmsBasedFilterInvocationDefinitionSource</class> 是基于数据库的权限存储实现, 它支持两种风格的配置 * @see com.skyon.uum.security.acegi.intercept.web.ConfigableFilterInvocationDefinition * @see org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap * @see org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap * @since 2006-1-19 * @author 王政 * @version $Id: RdbmsBasedFilterInvocationDefinitionSource.java,v 1.6 2006/02/13 03:20:55 wz Exp $ */public class RdbmsBasedFilterInvocationDefinitionSource extends AbstractFilterInvocationDefinitionSource  implements ConfigableFilterInvocationDefinition, InitializingBean {      //~ Static fields/initializers =============================================     private static final Log logger = LogFactory.getLog(RdbmsBasedFilterInvocationDefinitionSource.class);     // ~ Instance fields ========================================================     private String resourceExpression = PERL5_KEY;        private boolean convertUrlToLowercaseBeforeComparison = false;         private ResourceMappingProvider resourceMappingProvider;        //  ~ Methods ================================================================     /**  *   * @see org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource#lookupAttributes(java.lang.String)  */ public ConfigAttributeDefinition lookupAttributes(String url) {  FilterInvocationDefinitionSource actualSource = populateFilterInvocationDefinitionSource();    if (RegExpBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {   return ((RegExpBasedFilterInvocationDefinitionMap) actualSource).lookupAttributes(url);  } else if (PathBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {   return ((PathBasedFilterInvocationDefinitionMap) actualSource).lookupAttributes(url);  }    throw new IllegalStateException("wrong type of " + actualSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class     + " or " + PathBasedFilterInvocationDefinitionMap.class);   }  /**  *   * @see org.acegisecurity.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()  */ public Iterator getConfigAttributeDefinitions() {  FilterInvocationDefinitionSource actualSource = populateFilterInvocationDefinitionSource();    if (RegExpBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {   return ((RegExpBasedFilterInvocationDefinitionMap) actualSource).getConfigAttributeDefinitions();  } else if (PathBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {   return ((PathBasedFilterInvocationDefinitionMap) actualSource).getConfigAttributeDefinitions();  }    throw new IllegalStateException("wrong type of " + actualSource + ", it should be " + RegExpBasedFilterInvocationDefinitionMap.class     + " or " + PathBasedFilterInvocationDefinitionMap.class);  }      private FilterInvocationDefinitionSource populateFilterInvocationDefinitionSource() {                  FilterInvocationDefinitionMap definitionSource = null;          if (PERL5_KEY.equals(getResourceExpression())) {      definitionSource = new RegExpBasedFilterInvocationDefinitionMap();     } else if (ANT_PATH_KEY.equals(getResourceExpression())) {      definitionSource = new PathBasedFilterInvocationDefinitionMap();     } else {      throw new IllegalArgumentException("wrong resourceExpression value");     }                definitionSource.setConvertUrlToLowercaseBeforeComparison(isConvertUrlToLowercaseBeforeComparison());                ResourceMapping[] mappings = getResourceMappingProvider().getResourceMappings();        if (mappings == null || mappings.length ==0) {            return (FilterInvocationDefinitionSource) 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(STAND_DELIM_CHARACTER);                }            }            String value = valueBuffer.toString();                                addSecureUrl(definitionSource, mapping.getResourcePath(), value);         }             return (FilterInvocationDefinitionSource )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);    }        省去 getter, setter.... } ResourceMappingProvider public interface ResourceMappingProvider {     String RESOURCE_PATH_PREFIX = "/";     /**     * Get Resource Mapping     * @return resource mapping     */    ResourceMapping[] getResourceMappings();    } public class ResourceMapping {        // url    private String resourcePath;        // 即角色    private String[] recipients = new String[0];           省去 getter, setter.... }  这样就很完美的既支持了从数据库的读取数据, 又可以自由选择 Perl5 和 AntPath 两种风格的配置, 最后不要忘了给 ResourceMappingProvider 加一层 cache, 我的配置如下 <bean id="resourceCache" class="com.skyon.uum.security.acegi.intercept.web.cache.EhCacheBasedResourceCache">  <property name="dataSource">   <ref bean="dataSource"></ref>  </property>  <property name="cache">   <bean parent="cacheTemplate">        <property name="cacheName"><value>resourceCache</value></property>   </bean>        </property>  <property name="allResourcesQuery">   <value>   select distinct t.id, t.id, t.parent_id, t.url, t.title, t.layer, t.type, t.application_id   from uum_resource t order by t.orderField   </value>  </property> </bean>  <bean id="permissionCache" class="com.skyon.uum.security.acegi.intercept.web.cache.EhCacheBasedPermissionCache">  <property name="dataSource">   <ref bean="dataSource"></ref>  </property>  <property name="cache">   <bean parent="cacheTemplate">        <property name="cacheName"><value>permissionCache</value></property>   </bean>        </property>  <property name="recipentsResourceMappingQuery">   <value>   select r.name, p.resource_id from uum_permission p left outer join uum_role r on p.role_id = r.id   </value>  </property>  </bean>     <bean id="resourceMappingProvider" class="com.skyon.uum.security.acegi.intercept.web.ResourceMappingProviderImpl" autowire="byType"/>     <!-- ======================== AUTHENTICATION ======================= -->        <!-- Note the order that entries are placed against the objectDefinitionSource is critical.         The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.         Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->    <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">        <property name="authenticationManager"><ref local="authenticationManager"/></property>        <property name="accessDecisionManager"><ref local="accessDecisionManager"/></property>        <property name="objectDefinitionSource"><ref local="filterInvocationDefinitionSource"></ref></property>  <!--  <property name="rejectPublicInvocations"><value>true</value></property>  -->    </bean>  <bean id="filterInvocationDefinitionSource" class="com.skyon.uum.security.acegi.intercept.web.RdbmsBasedFilterInvocationDefinitionSource">  <property name="resourceMappingProvider">   <ref local="resourceMappingProvider"></ref>  </property>  <property name="resourceExpression">   <value>PATTERN_TYPE_APACHE_ANT</value>  </property> </bean>


阅读全文(3231) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.219 second(s), page refreshed 144800692 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号