- 浏览: 359505 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
呆呆DE萌萌:
不可以吗?Timer里不是有一个指定首次运行时间firstDa ...
在Spring中使用 Java Timer 调度任务 -
accpchf:
不太明白,Error jvm都已经停止线程了,怎么还能转译?
深入探索 高效的Java异常处理框架。 -
bo_hai:
讲的详细。谢谢!
详解spring2.0的scope -
hpjianhua:
学习下...
线程池的实现 -
eltonto:
以后你可以来这里看看favicon在线转换
Tomcat中使用Favicon
1. 问题提出
在使用 Acegi Security Framework 的过程中, 如果细心的话, 会发现其资源和角色配置是在配置文件中的, 下面是 Appfuse 中相关配置 :
上面的配置从功能上实现了资源与角色的映射, 但用户可能会提出在运行期动态改变权限分配的需求, 配置文件策略可能略显不足, 下面我将提供一种基于数据库的策略解决此问题.
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 来覆盖默认实现, 下面是我的 配置 :
那么, 这个 PropertyEditor 中需要做些什么呢 ? 要做的就是使用一个比较特殊的标记, 当遇到这个特殊标记的时候直接略过解析, 我这里使用的标记是 “DONT_USE_ME”, 然后在 PropertyEditor 中简单的如下实现即可:
Ok, 现在 FilterInvocationDefinitionSourceDynamicExtentionEditor 遇到配置文件中的 “DONT_USE_ME” 时将直接略过, 下面是我的 filterInvocationInterceptor 配置:
现在, 我们已经成功阻止 acegi 从配置文件读取权限配置, 下一个问题就是:
4. 如何从表中数据组装 FilterInvocationDefinitionSource
为了实现此功能, 需要一个自定义的资源定义接口来提供 FilterInvocationDefinitionSource, 此接口可能会是这样 :
其核心方法是 FilterInvocationDefinitionSource getFilterInvocationDefinitionSource(), 此方法将代替配置文件提供资源和角色的配置, 下面是实现
实现采用 EhCache 缓存资源权限配置, 这样如果资源权限数据发生变化, 可以 flush Cache 从数据库重新读取. 至于代码中的 ResourceMapingProvider 实现, 简单的把 Resource 表和 Role 表中的数据读取过来即可, 这里不再赘述.
5. 如何将数据库中的权限配置传递给 FilterInvocationInterceptor
完成以上步骤后, 最后一步就是如何把 FilterInvocationDefinitionSourceCache 中的 FilterInvocationDefinitionSource 传递给 FilterInvocationInterceptor, Simple implemention :
配置:
在使用 Acegi Security Framework 的过程中, 如果细心的话, 会发现其资源和角色配置是在配置文件中的, 下面是 Appfuse 中相关配置 :
<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 /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 来覆盖默认实现, 下面是我的 配置 :
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource"> <bean id="filterInvocationDefinitionSourceDaoExtentionEditor" class="com.skyon.um.security.acegi.intercept.web.FilterInvocationDefinitionSourceDynamicExtentionEditor" > </bean> </entry> </map> </property> </bean>
那么, 这个 PropertyEditor 中需要做些什么呢 ? 要做的就是使用一个比较特殊的标记, 当遇到这个特殊标记的时候直接略过解析, 我这里使用的标记是 “DONT_USE_ME”, 然后在 PropertyEditor 中简单的如下实现即可:
/* * 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 $ */ public class FilterInvocationDefinitionSourceDynamicExtentionEditor extends PropertyEditorSupport { public static final String ANT_PATH_KEY = "PATTERN_TYPE_APACHE_ANT"; public static final String LOWER_CASE_URL_KEY = "CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON"; public static final String DONT_USE_ME_KEY = "DONT_USE_ME"; public static final String STAND_DELIM_CHARACTER = ","; private static final Log logger = LogFactory.getLog(FilterInvocationDefinitionSourceDynamicExtentionEditor.class); /** * @see java.beans.PropertyEditorSupport#setAsText(java.lang.String) */ public void setAsText(String text) throws IllegalArgumentException { 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 = new BufferedReader(new StringReader(text)); int counter = 0; String line; while (true) { counter++; try { line = br.readLine(); } catch (IOException ioe) { throw new IllegalArgumentException(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 */ private 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); } }
Ok, 现在 FilterInvocationDefinitionSourceDynamicExtentionEditor 遇到配置文件中的 “DONT_USE_ME” 时将直接略过, 下面是我的 filterInvocationInterceptor 配置:
<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> DONT_USE_ME </value> </property> </bean>
现在, 我们已经成功阻止 acegi 从配置文件读取权限配置, 下一个问题就是:
4. 如何从表中数据组装 FilterInvocationDefinitionSource
为了实现此功能, 需要一个自定义的资源定义接口来提供 FilterInvocationDefinitionSource, 此接口可能会是这样 :
/* * 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 $ */ public interface 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(), 此方法将代替配置文件提供资源和角色的配置, 下面是实现
/* * 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 $ */ public class EhCacheBasedFilterInvocationDefinitionSourceCache extends MandatorySingletonBeanSupport implements FilterInvocationDefinitionSourceCache, InitializingBean { private static final Log logger = LogFactory.getLog(EhCacheBasedFilterInvocationDefinitionSourceCache.class); private int resourceExpression; private boolean convertUrlToLowercaseBeforeComparison = false; private ResourceMappingProvider resourceMappingProvider; private Cache cache; private Object lock = new Object(); /** * @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 = new Element("key", new SerializableObjectProvider(definitionSource)); getCache().put(element); } return (FilterInvocationDefinitionSource) ((SerializableObjectProvider) element.getValue()).getSourceObject(); } } public void 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 :
/* * Copyright 2005-2010 the original author or autors * * http://www.skyon.com.cn * * Project { SkyonFramwork } */ package com.skyon.um.security.acegi.intercept.web; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.InsufficientAuthenticationException; import net.sf.acegisecurity.context.SecurityContextHolder; import net.sf.acegisecurity.intercept.web.FilterInvocation; import net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; /** * @see com.skyon.um.security.acegi.intercept.web.FilterInvocationDefinitionSourceCache * @see com.skyon.um.security.acegi.intercept.event.FilterInvocationDefinitionSourceChangedEvent * @see com.skyon.um.security.acegi.intercept.event.FilterInvocationDefinitionSourceListener * @since 2005-8-7 * @author 王政 * @version $Id: SecurityEnforcementDynamicExtensionFilter.java,v 1.5 2005/12/05 02:40:52 wangzheng Exp $ */ public class SecurityEnforcementDynamicExtensionFilter extends SecurityEnforcementFilter implements InitializingBean { private static final Log logger = LogFactory.getLog(SecurityEnforcementDynamicExtensionFilter.class); private FilterInvocationDefinitionSourceCache definitionSourceCache; private boolean forbiddenAnyAnonymousVisit = false; /** * @return Returns the definitionSourceCache. */ public FilterInvocationDefinitionSourceCache getDefinitionSourceCache() { return definitionSourceCache; } /** * @param definitionSourceCache The definitionSourceCache to set. */ public void setDefinitionSourceCache(FilterInvocationDefinitionSourceCache definitionSourceHolder) { this.definitionSourceCache = definitionSourceHolder; } /** * @return Returns the forbiddenAnyAnonymousVisit. */ public boolean isForbiddenAnyAnonymousVisit() { return forbiddenAnyAnonymousVisit; } /** * 设定是否任何资源都不允许匿名访问, 注意如果设置 为 true, /login.jsp 一定不能使用此 Filter, 否则会死循环! * @param forbiddenAnyAnonymousVisit The forbiddenAnyAnonymousVisit to set. */ public void setForbiddenAnyAnonymousVisit(boolean forbiddenAnyAnonymousVisit) { this.forbiddenAnyAnonymousVisit = forbiddenAnyAnonymousVisit; } /** * @see net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); Assert.notNull(getDefinitionSourceCache(), " definitionSourceCache must be specified "); } /** * 从 {@link FilterInvocationDefinitionSourceCache} 中读取 {@link net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource} * @see net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // get the defination source form soure holder getFilterSecurityInterceptor().setObjectDefinitionSource(getDefinitionSourceCache().getFilterInvocationDefinitionSource()); if (!(request instanceof HttpServletRequest)) { throw new ServletException("HttpServletRequest required"); } if (!(response instanceof HttpServletResponse)) { throw new ServletException("HttpServletResponse required"); } boolean continueDoFilter = true; /** 任何匿名访问都将定位到登陆页面, 注意如果 {@link #isForbiddenAnyAnonymousVisit()} 为 true, /login.jsp 一定不能使用此 Filter, 否则会死循环! */ if (isForbiddenAnyAnonymousVisit()) { FilterInvocation fi = new FilterInvocation(request, response, chain); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || getAuthenticationTrustResolver().isAnonymous(authentication)) { if (logger.isDebugEnabled()) { logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point"); } continueDoFilter = false; sendStartAuthentication(fi, new InsufficientAuthenticationException( "Full authentication is required to access this resource")); } } if (continueDoFilter) { super.doFilter(request, response, chain); } } }
配置:
<bean id="securityEnforcementFilter" class="com.skyon.um.security.acegi.intercept.web.SecurityEnforcementDynamicExtensionFilter"> <property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property> <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property> <property name="definitionSourceCache"> <ref local="filterInvocationDefinitionSourceCache"></ref> </property> <property name="forbiddenAnyAnonymousVisit"><value>true</value></property> </bean>
发表评论
-
Pathway from ACEGI to Spring Security 2.0
2008-06-26 11:02 3991Free Open Source Project Host ... -
Get All Connected Users
2008-06-25 21:17 1428Sometimes you may be wanna get ... -
Bug : LogoutFilter return a 404 on Websphere 6.0.2
2008-01-16 14:36 1657Environment: Windows Xp + Webs ... -
扩展acegi以支持验证码等
2008-01-05 11:14 3129主要是通用改写扩展authenticationProcessi ... -
Acegi 组件概览
2008-01-05 10:50 12171.Filter 组件 HttpSessionContext ...
相关推荐
1. **源代码**:展示如何配置Acegi Security的XML文件,以及如何在Java代码中实现自定义的安全逻辑。 2. **测试类**:可能包含了用于测试不同安全场景的JUnit测试,这些测试可以帮助我们理解Acegi Security的各种...
### Acegi的详细配置实现 #### 一、整体架构概览 **Acegi Security** 是一个为Spring框架设计的安全管理工具,它提供了丰富的安全服务,包括认证(Authentication)、授权(Authorization)以及会话管理(Session ...
标题 "batis+acegi实现的动态权限控制" 暗示了这个项目是关于整合Spring框架中的Acegi安全模块和MyBatis ORM框架,来创建一个动态的权限管理系统。Acegi是Spring早期的安全组件,现在已被Spring Security所取代,但...
Acegi 安全框架是Spring生态...综上所述,这个资源对于理解和实施Acegi安全框架,特别是涉及动态数据库配置和权限控制的场景,具有很高的参考价值。开发者可以通过学习这些内容,提升自己在Spring安全方面的专业能力。
- "aopacegi"可能是一个包含Acegi与AOP相关配置或实现的文件,可能涉及切面的定义和安全策略的配置。 Acegi Security在过去的开发实践中扮演了重要角色,它的设计理念和实现方式对后来的安全框架产生了深远影响。...
由于Acegi默认配置文件策略可能无法满足所有场景下的需求,尤其是在需要动态调整用户权限的情况下。为了解决这一问题,可以采用基于数据库的策略来进行动态扩展。 - **基于数据库的策略**: 1. 将权限信息存储在...
4. **实现认证和授权逻辑**:根据应用需求,实现自定义的认证和授权类,这些类通常会扩展Acegi提供的基础类。 5. **测试和调试**:在实际运行环境中测试安全功能,确保用户权限设置正确,并使用Acegi提供的日志和...
总之,AceGI作为一个强大的安全框架,通过灵活的配置和扩展机制,使开发者能轻松地在Web应用中实现复杂的安全控制。它不仅支持基本的认证和授权,还允许自定义逻辑以适应各种业务场景。通过理解和熟练运用AceGI,...
本主题将深入探讨如何使用Acegi安全框架和Hibernate ORM工具动态实现基于角色的权限管理。Acegi(现已被Spring Security替代)是一个用于Java平台的安全框架,而Hibernate则是一个流行的关系型数据库持久化解决方案...
开发者可以在不改变业务逻辑的情况下,通过配置实现复杂的权限管理。尽管现在Spring Security已经成为更推荐的安全解决方案,但Acegi在早期对Spring应用的安全支持起到了重要作用,其设计理念和实现方式在Spring ...
这篇博客将深入解析一个配置了Acegi Security的`applicationContext-acegi-security.xml`文件,帮助我们理解如何将LDAP与Acegi集成以实现更安全的Web应用。 **LDAP基础** LDAP是一种标准的网络协议,用于存储和...
Acegi的主要目标是实现业务对象方法级别的安全控制,确保URL资源、业务类方法以及领域对象的访问得到适当限制。 1. URL资源的访问控制:Acegi能够设定不同用户群体对网页资源的访问权限。例如,所有用户可以访问...
Acegi还支持动态权限评估,允许在运行时根据特定条件决定用户是否有权访问资源。 接下来,我们讨论如何在Spring框架下实现这个系统。Spring的依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented...
用户无需编写大量代码,只需通过配置即可实现应用程序的安全管理。Acegi的主要优点在于其灵活性和可扩展性,能够方便地集成到Spring应用中,为用户提供了细粒度的权限控制。 在配置Acegi时,首先需要在`web.xml`...
3. **安全拦截**:Acegi利用Spring的AOP框架来实现对方法调用和URL访问的拦截。你可以定义安全拦截规则,例如,只有特定角色的用户才能访问某个方法或页面。 4. **角色与权限**:在Acegi中,用户可以被分配多个角色...
在处理复杂的权限管理时,Acegi允许开发者将资源权限数据存储到数据库,而不是仅局限于配置文件中,这样可以实现更灵活的权限动态扩展。 在传统的Acegi配置中,资源和角色的关系通常是硬编码在XML配置文件内的,...
Spring Acegi是一个安全框架,它为Spring...虽然Spring Acegi已不再更新,但其核心思想和机制在Spring Security中得到了继承和扩展。理解这个简单实例有助于你更好地理解和应用更现代的安全框架,如Spring Security。
通过这个实例,开发者可以学习如何配置Acegi的安全策略,如何在Spring应用中设置LDAP连接,以及如何设计和实现基于角色的访问控制(RBAC)。这有助于构建更健壮、安全的企业级应用,尤其适合大型组织和制造业等需要...