最近在研究spring的认证框架acegi,记录一下自己的理解。
Acegi是基于Spring的一个开源的安全认证框架,现在的最新版本是1.0.7。Acegi的特点就是有很多的过滤器,具体项目中能用到哪些过滤器,则进行配置即可。
Acegi资源包下载: http://mirrors.ibiblio.org/pub/mirrors/maven2/org/acegisecurity/acegi-security/
Acegi的官网: http://www.acegisecurity.org/
Acegi是以过滤器的方式来使用的,在WEB程序中,就得在web.xml中配置过滤器,如果在web.xml配置许多的过滤器,肯定会出现配置文件过大和初始化及Filter的管理得问题,Acegi提供了用spring容器来管理Filter的配置方式:
Web.xml文件中:
<filter>
<filter-name>Acegi-Filter</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>
applicationContext-acegi-security.xml文件中:
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/j_acegi_security_check*=httpSessionContextIntegrationFilter,authenticationProcessingFilter
/**/*=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
让我们来看看发生了什么:
在FilterToBeanProxy类中还可以配置的参数有targetBean,它代表spring容器中Bean对象,而targetClass这代表Bean容器中配置的Filter。配置他们可以达到同样的效果,就是从spring容器中的到相应的Bean对象,也就是FilterChainProxy对象。当请求被Acegi-Filter过滤器截获后,FilterToBeanProxy将请求交给FilterChainProxy对象处理。当FilterChainProxy接受请求时,它首先根据filterInvocationDefinitionSource的配置来得到本次请求所要经过的过滤器列表。FilterInvocationDefinitionSource有多个实现类。其中用的较多的是PathBaseFilterInvocationDefinitionMap类。他将配置的每一个Key-Value对封装成一个EntryHolder对象,然后保存在requestMap的list中。PathBaseFilterInvocationDefinitionMap会首先得到请求的url,然后根据这个url在requestMap找到符合条件的EntryHolder对象,然后得到ConfigAttributeDefinition对象,其中保存的是配置的Filter列表:PathBaseFilterInvocationDefinitionMap:lookAttributes(String url)
Iterator iter = requestMap.iterator();
while (iter.hasNext()) {
EntryHolder entryHolder = (EntryHolder) iter.next();
//判断请求的url与配置的path是否相符
boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);
if (logger.isDebugEnabled()) {
logger.debug("Candidate is: '" + url + "'; pattern is " + entryHolder.getAntPath() + "; matched="
+ matched);
}
if (matched) {//如果找到,这返回EntryHolder中的ConfigAttributeDefinition对象,其中保存有对应的Filter列表
return entryHolder.getConfigAttributeDefinition();
}
}
得到了ConfigAttributeDefinition对象,然后得到其中的所有的Filter:
PathBaseFilterInvocationDefinitionMap:obtainAllDefinedFilter(ConfigAttributeDefinition configAttributeDefinition)
Iterator attributes = configAttributeDefinition.getConfigAttributes();
while (attributes.hasNext()) {
ConfigAttribute attr = (ConfigAttribute) attributes.next();
String filterName = attr.getAttribute();
if (filterName == null) {
throw new IllegalArgumentException("Configuration attribute: '" + attr
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
}
if (!filterName.equals(TOKEN_NONE)) {
list.add(this.applicationContext.getBean(filterName, Filter.class));
}
}
return (Filter[]) list.toArray(new Filter[list.size()]);
其中我们看到如果filterName.equals(TOKEN_NONE),则这个Filter不加入到处理的Filter对列中,所以如果要想某个请求不经过这些过滤器,则可以配成:path=#NONE#
然后FilterChainProxy将所有的过滤器保存在一个VirtualFilterChain对象中,将所有过滤器的调用交给VirtualFilterChain对象:VirtualFilterChain:
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if (currentPosition == additionalFilters.length) {
if (logger.isDebugEnabled()) {
logger.debug(fi.getRequestUrl()
+ " reached end of additional filter chain; proceeding with original chain");
}
fi.getChain().doFilter(request, response);
} else {
currentPosition++;
if (logger.isDebugEnabled()) {
logger.debug(fi.getRequestUrl() + " at position " + currentPosition + " of "
+ additionalFilters.length + " in additional filter chain; firing Filter: '"
+ additionalFilters[currentPosition - 1] + "'");
}
additionalFilters[currentPosition - 1].doFilter(request, response, this);
}
}
这样VirtualFilterChain将按filterChainProxy中配置的Filter顺序来一个个执行。
Acegi认证详解
5917

被折叠的 条评论
为什么被折叠?



