在实际应用中,开发者有时需要将Web资源授权信息(角色与授权资源之间的定义)存放在RDBMS中,以便更好的管理。事实上,我觉得一般的企业应用都应当如此,因为这样可以使角色和Web资源的管理更灵活,更自由。那么,我们应当如何实现这个需求呢?在接下来的内容当中,我们将一一解说。
      我们都知道,一般Web资源授权信息的配置类似如下代码:

  1. <bean id="filterInvocationInterceptor"
  2. class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  3. ……
  4. <property name="objectDefinitionSource">
  5. <value>
  6. <![CDATA[
  7. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
  8. PATTERN_TYPE_APACHE_ANT
  9. /secure/**=ROLE_SUPERVISOR
  10. /authenticate/**=ROLE_USER,ROLE_SUPERVISOR
  11. /**=IS_AUTHENTICATED_ANONYMOUSLY
  12. ]]>
  13. </value>
  14. </property>
  15. </bean>
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
……
<property name="objectDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/secure/**=ROLE_SUPERVISOR
/authenticate/**=ROLE_USER,ROLE_SUPERVISOR
/**=IS_AUTHENTICATED_ANONYMOUSLY
]]>
</value>
</property>
</bean>

objectDefinitionSource 属性定义发Web资源授权信息(角色与授权资源之间的关系)
      objectDefinitionSource 属性指定了”PATTERN_TYPE_APACHE_ANT”,即希望启用Apache Ant路径风格的URL匹配模式,则FilterInvocationDefinitionSourceEditor会实例化PathBasedFilterInvocationDefinitionMap实例。如果未指定这一字符串,即希望采用默认的正是表达式,则RegExpBasedFilterInvocationDefinitionMap会被实例化。注意,PathBasedFilterInvocationDefinitionMap和RegExpBasedFilterInvocationDefinitionMap都是FilterInvocationDefinitionSource的实现类。

当Web容器装载Acegi时,Spring会自动找到FilterInvocationDefinitionSourceEditor属性编辑器,并采用它解析上述Web资源授权信息。由于FilterInvocationDefinitionSource同FilterInvocationDefinitionSourceEditor处在同一个Java包中,因此开发者不用显式注册这一属性编辑器,Spring会透明地为开发者考虑到这一切。
      为了能够通过RDBMS维护Web资源授权信息,我们必须提供自身的FilterInvocationDefinitionSource实现类。

Acegi 安全系统需要记录一些配置信息,这些配置信息用于各种可能的请求。为了存储针对各种不同请求的各种安全配置,就要使用配置属性。在实现上配置属性通过ConfigAttribute接口来表示。SecurityConfig是ConfigAttribute接口的一个具体实现,它简单地把配置属性当作一个串(String)来存储。

与特定请求相联系的ConfigAttributes 集合保存在ConfigAttributeDefinition中。这个类只是一个简单的ConfigAttributes存储器,并不做其它特别的处理。

当安全性拦截器收到一个请求时,它需要判断使用哪些配置属性。换句话说,它需要找到用于这种请求的ConfigAttributeDefinition.这种判别是通过ObjectDefinitionSource接口来处理的.这个接口提供的主要方法是 public ConfigAttributeDefinition getAttributes(Object object),其中的Object 就是要保护的安全对象。因为安全对象包含了请求的细节,所以ObjectDefinitionSource实现类将能够抽取它所需要的细节来检查相关的ConfigAttributeDefinition。

 1、 增加Web资源授权信息表

  1. create table webresdb(
  2. id bigint not null primary key,
  3. url varchar(60) not null,
  4. roles varchar(100) not null
  5. );
  6. INSERT INTO WEBRESDB VALUES(1,'/secure/**','ROLE_SUPERVISOR')
  7. INSERT INTO WEBRESDB VALUES(2,'/authenticate/**','ROLE_USER,ROLE_SUPERVISOR')
  8. INSERT INTO WEBRESDB VALUES(3,'/**','IS_AUTHENTICATED_ANONYMOUSLY')
create table webresdb(
id bigint not null primary key,
url varchar(60) not null,
roles varchar(100) not null
);
INSERT INTO WEBRESDB VALUES(1,'/secure/**','ROLE_SUPERVISOR')
INSERT INTO WEBRESDB VALUES(2,'/authenticate/**','ROLE_USER,ROLE_SUPERVISOR')
INSERT INTO WEBRESDB VALUES(3,'/**','IS_AUTHENTICATED_ANONYMOUSLY')

2、增加类似于EntryHolder的辅助类RdbmsEntryHolder
      通过分析PathBasedFilterInvocationDefinitionMap类,我们发现,对于每行Web  资源授权需求,比如“/secure/**=ROLE_SUPERVISOR”,它会借助于内部类EntryHolder存储各行内容。EntryHolder暴露了antPath和configAttributeDefinition属性,前者存储类似“/secure/**”的内容,而后者会通过configAttributeDefinition对象存储类似“ROLE_USER,ROLE_SUPERVISOR”的内容。在ConfigAttributeDefinition对象内部,它将各个角色拆分开,并分别借助SecurityConfig对象存储它们,即ROLE_USER和ROLE_SUPERVISOR,从而保存在configAttributes私有变量中。
      在此,我们提供了类似于EntryHolder的辅助类:

  1. public class RdbmsEntryHolder implements Serializable {
  2. private static final long serialVersionUID = 2317309106087370323L;
  3. // 保护的URL模式
  4. private String url;
  5. // 要求的角色集合
  6. private ConfigAttributeDefinition cad;
  7. public String getUrl() {
  8. return url;
  9. }
  10. public ConfigAttributeDefinition getCad() {
  11. return cad;
  12. }
  13. public void setUrl(String url) {
  14. this.url = url;
  15. }
  16. public void setCad(ConfigAttributeDefinition cad) {
  17. this.cad = cad;
  18. }
  19. }
public class RdbmsEntryHolder implements Serializable {
private static final long serialVersionUID = 2317309106087370323L;
// 保护的URL模式
private String url;
// 要求的角色集合
private ConfigAttributeDefinition cad;
public String getUrl() {
return url;
}
public ConfigAttributeDefinition getCad() {
return cad;
}
public void setUrl(String url) {
this.url = url;
}
public void setCad(ConfigAttributeDefinition cad) {
this.cad = cad;
} }

3、增加从RDBMS装载所有的Web资源授权信息的类

  1. public class RdbmsSecuredUrlDefinition extends MappingSqlQuery{
  2. protected static final Log logger = LogFactory.getLog(RdbmsSecuredUrlDefinition.class);
  3. protected RdbmsSecuredUrlDefinition(DataSource ds) {
  4. super(ds, Constants.ACEGI_RDBMS_SECURED_SQL);
  5. logger.debug("进入到RdbmsInvocationDefinition构建器中.........");
  6. compile();
  7. }
  8. /**
  9. * convert each row of the ResultSet into an object of the result type.
  10. */
  11. protected Object mapRow(ResultSet rs, int rownum)
  12. throws SQLException {
  13. logger.debug("抽取webresdb中的记录.........");
  14. RdbmsEntryHolder rsh = new RdbmsEntryHolder();
  15. // 设置URL
  16. rsh.setUrl(rs.getString(Constants.ACEGI_RDBMS_SECURED_URL).trim());
  17. ConfigAttributeDefinition cad = new ConfigAttributeDefinition();
  18. String rolesStr = rs.getString(Constants.ACEGI_RDBMS_SECURED_ROLES).trim();
  19. // commaDelimitedListToStringArray:Convert a CSV list into an array of Strings
  20. // 以逗号为分割符, 分割字符串
  21. String[] tokens =
  22. StringUtils.commaDelimitedListToStringArray(rolesStr); // 角色名数组
  23. // 构造角色集合
  24. for(int i = 0; i < tokens.length;++i)
  25. cad.addConfigAttribute(new SecurityConfig(tokens[i]));
  26. //设置角色集合
  27. rsh.setCad(cad);
  28. return rsh;
  29. }
  30. }
public class RdbmsSecuredUrlDefinition extends MappingSqlQuery{

	protected static final Log logger = LogFactory.getLog(RdbmsSecuredUrlDefinition.class);

    protected RdbmsSecuredUrlDefinition(DataSource ds) {
super(ds, Constants.ACEGI_RDBMS_SECURED_SQL);
logger.debug("进入到RdbmsInvocationDefinition构建器中........."); compile();
} /**
* convert each row of the ResultSet into an object of the result type.
*/
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
logger.debug("抽取webresdb中的记录........."); RdbmsEntryHolder rsh = new RdbmsEntryHolder();
// 设置URL
rsh.setUrl(rs.getString(Constants.ACEGI_RDBMS_SECURED_URL).trim()); ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); String rolesStr = rs.getString(Constants.ACEGI_RDBMS_SECURED_ROLES).trim();
// commaDelimitedListToStringArray:Convert a CSV list into an array of Strings
// 以逗号为分割符, 分割字符串
String[] tokens =
StringUtils.commaDelimitedListToStringArray(rolesStr); // 角色名数组
// 构造角色集合
for(int i = 0; i < tokens.length;++i)
cad.addConfigAttribute(new SecurityConfig(tokens[i])); //设置角色集合
rsh.setCad(cad); return rsh;
} }

这样,我们可以利用RdbmsSecuredUrlDefinition将webresdb中的各行记录组装成RdbmsEntryHolder对象,进而返回RdbmsEntryHolder集合给调用者。

4、增加FilterInvocationDefinitionSource的实现类

  1. /**
  2. * FilterInvocationDefinitionSource实现类1
  3. *
  4. * @author qiuzj
  5. *
  6. */
  7. public class RdbmsFilterInvocationDefinitionSource extends JdbcDaoSupport
  8. implements FilterInvocationDefinitionSource {
  9. protected static final Log logger = LogFactory.getLog(RdbmsFilterInvocationDefinitionSource.class);
  10. private RdbmsSecuredUrlDefinition rdbmsInvocationDefinition;
  11. private PathMatcher pathMatcher = new AntPathMatcher();
  12. private Ehcache webresdbCache;
  13. /**
  14. * 实现ObjectDefinitionSource接口的方法
  15. * 最核心的方法, 几乎可以认为RdbmsFilterInvocationDefinitionSource的其他大部分方法都是为这一方法服务的
  16. *
  17. * Accesses the <code>ConfigAttributeDefinition</code> that applies to a given secure object.<P>Returns
  18. * <code>null</code> if no <code>ConfigAttribiteDefinition</code> applies.</p>
  19. *
  20. * @param object the object being secured
  21. *
  22. * @return the <code>ConfigAttributeDefinition</code> that applies to the passed object
  23. * @返回 适用于传入对象的ConfigAttributeDefinition(角色集合)
  24. *
  25. * @throws IllegalArgumentException if the passed object is not of a type supported by the
  26. *         <code>ObjectDefinitionSource</code> implementation
  27. */
  28. public ConfigAttributeDefinition getAttributes(Object object)
  29. throws IllegalArgumentException {
  30. if ((object == null) || !this.supports(object.getClass())) {
  31. throw new IllegalArgumentException("抱歉,目标对象不是FilterInvocation类型");
  32. }
  33. // 抽取出待请求的URL
  34. String url = ((FilterInvocation) object).getRequestUrl();
  35. logger.info("待请示的URL: " + url);
  36. // 获取所有RdbmsEntryHolder列表(url与角色集合对应列表)
  37. List list = this.getRdbmsEntryHolderList();
  38. if (list == null || list.size() == 0)
  39. return null;
  40. // 去掉待请求url参数信息
  41. int firstQuestionMarkIndex = url.indexOf("?");
  42. if (firstQuestionMarkIndex != -1) {
  43. url = url.substring(0, firstQuestionMarkIndex);
  44. }
  45. Iterator iter = list.iterator();
  46. // 循环判断用户是否有权限访问当前url, 有则返回ConfigAttributeDefinition(角色集合)
  47. while (iter.hasNext()) {
  48. RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
  49. // 判断当前访问的url是否符合entryHolder.getUrl()模式, 即判断用户是否有权限访问当前url
  50. // 如url="/secure/index.jsp", entryHolder.getUrl()="/secure/**", 则有权限访问
  51. boolean matched = pathMatcher.match(entryHolder.getUrl(), url);
  52. if (logger.isDebugEnabled()) {
  53. logger.debug("匹配到如下URL: '" + url + ";模式为 "
  54. + entryHolder.getUrl() + ";是否被匹配:" + matched);
  55. }
  56. // 如果在用户所有被授权的URL中能找到匹配的, 则返回该ConfigAttributeDefinition(角色集合)
  57. if (matched) {
  58. return entryHolder.getCad();
  59. }
  60. }
  61. return null;
  62. }
  63. /**
  64. * 实现接口方法
  65. *
  66. * If available, all of the <code>ConfigAttributeDefinition</code>s defined by the implementing class.<P>This
  67. * is used by the {@link AbstractSecurityInterceptor} to perform startup time validation of each
  68. * <code>ConfigAttribute</code> configured against it.</p>
  69. *
  70. * @return an iterator over all the <code>ConfigAttributeDefinition</code>s or <code>null</code> if unsupported
  71. * @返回 ConfigAttributeDefinition迭代集合(Iterator)
  72. */
  73. public Iterator getConfigAttributeDefinitions() {
  74. Set set = new HashSet();
  75. Iterator iter = this.getRdbmsEntryHolderList().iterator();
  76. while (iter.hasNext()) {
  77. RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
  78. set.add(entryHolder.getCad());
  79. }
  80. return set.iterator();
  81. }
  82. /**
  83. * 实现接口方法, 检验传入的安全对象是否是与FilterInvocation类相同类型, 或是它的子类
  84. * getAttributes(Object object)方法会调用这个方法
  85. * 保证String url = ((FilterInvocation) object).getRequestUrl();的正确性
  86. *
  87. * Indicates whether the <code>ObjectDefinitionSource</code> implementation is able to provide
  88. * <code>ConfigAttributeDefinition</code>s for the indicated secure object type.
  89. *
  90. * @param clazz the class that is being queried
  91. *
  92. * @return true if the implementation can process the indicated class
  93. */
  94. public boolean supports(Class clazz) {
  95. if (FilterInvocation.class.isAssignableFrom(clazz)) {
  96. return true;
  97. } else {
  98. return false;
  99. }
  100. }
  101. /**
  102. * 覆盖JdbcDaoSupport中的方法, 用于将数据源传入RdbmsSecuredUrlDefinition中
  103. * JdbcDaoSupport实现了InitializingBean接口, 该接口中的afterPropertiesSet()方法
  104. * 用于在所有spring bean属性设置完毕后做一些初始化操作, BeanFactory会负责调用它
  105. * 而在JdbcDaoSupport的实现中, afterPropertiesSet()方法调用了initDao()方法, 故我们
  106. * 借此做一些初始化操作.
  107. * 在此用于将数据源传入RdbmsSecuredUrlDefinition中
  108. */
  109. protected void initDao() throws Exception {
  110. logger.info("第一个执行的方法: initDao()");
  111. this.rdbmsInvocationDefinition =
  112. new RdbmsSecuredUrlDefinition(this.getDataSource()); // 传入数据源, 此数据源由Spring配置文件注入
  113. if (this.webresdbCache == null)
  114. throw new IllegalArgumentException("必须为RdbmsFilterInvocationDefinitionSource配置一EhCache缓存");
  115. }
  116. /**
  117. * 获取所有RdbmsEntryHolder列表(url与角色集合对应列表)
  118. *
  119. * @return
  120. */
  121. private List getRdbmsEntryHolderList(){
  122. List list = null;
  123. Element element = this.webresdbCache.get("webres");
  124. if (element != null){ // 如果缓存中存在RdbmsEntryHolder列表, 则直接获取返回
  125. list = (List) element.getValue();
  126. } else { // 如果缓存中不存在RdbmsEntryHolder列表, 则重新查询, 并放到缓存中
  127. list = this.rdbmsInvocationDefinition.execute();
  128. Element elem = new Element("webres", list);
  129. this.webresdbCache.put(elem);
  130. }
  131. //list = this.rdbmsInvocationDefinition.execute();
  132. return list;
  133. }
  134. /**
  135. * 用于Spring注入
  136. *
  137. * @param webresdbCache
  138. */
  139. public void setWebresdbCache(Ehcache webresdbCache) {
  140. this.webresdbCache = webresdbCache;
  141. }
  142. }
/**
* FilterInvocationDefinitionSource实现类1
*
* @author qiuzj
*
*/
public class RdbmsFilterInvocationDefinitionSource extends JdbcDaoSupport
implements FilterInvocationDefinitionSource { protected static final Log logger = LogFactory.getLog(RdbmsFilterInvocationDefinitionSource.class); private RdbmsSecuredUrlDefinition rdbmsInvocationDefinition; private PathMatcher pathMatcher = new AntPathMatcher(); private Ehcache webresdbCache; /**
* 实现ObjectDefinitionSource接口的方法
* 最核心的方法, 几乎可以认为RdbmsFilterInvocationDefinitionSource的其他大部分方法都是为这一方法服务的
*
* Accesses the <code>ConfigAttributeDefinition</code> that applies to a given secure object.<P>Returns
* <code>null</code> if no <code>ConfigAttribiteDefinition</code> applies.</p>
*
* @param object the object being secured
*
* @return the <code>ConfigAttributeDefinition</code> that applies to the passed object
* @返回 适用于传入对象的ConfigAttributeDefinition(角色集合)
*
* @throws IllegalArgumentException if the passed object is not of a type supported by the
* <code>ObjectDefinitionSource</code> implementation
*/
public ConfigAttributeDefinition getAttributes(Object object)
throws IllegalArgumentException {
if ((object == null) || !this.supports(object.getClass())) {
throw new IllegalArgumentException("抱歉,目标对象不是FilterInvocation类型");
} // 抽取出待请求的URL
String url = ((FilterInvocation) object).getRequestUrl();
logger.info("待请示的URL: " + url); // 获取所有RdbmsEntryHolder列表(url与角色集合对应列表)
List list = this.getRdbmsEntryHolderList();
if (list == null || list.size() == 0)
return null; // 去掉待请求url参数信息
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
} Iterator iter = list.iterator();
// 循环判断用户是否有权限访问当前url, 有则返回ConfigAttributeDefinition(角色集合)
while (iter.hasNext()) {
RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
// 判断当前访问的url是否符合entryHolder.getUrl()模式, 即判断用户是否有权限访问当前url
// 如url="/secure/index.jsp", entryHolder.getUrl()="/secure/**", 则有权限访问
boolean matched = pathMatcher.match(entryHolder.getUrl(), url); if (logger.isDebugEnabled()) {
logger.debug("匹配到如下URL: '" + url + ";模式为 "
+ entryHolder.getUrl() + ";是否被匹配:" + matched);
} // 如果在用户所有被授权的URL中能找到匹配的, 则返回该ConfigAttributeDefinition(角色集合)
if (matched) {
return entryHolder.getCad();
}
} return null;
} /**
* 实现接口方法
*
* If available, all of the <code>ConfigAttributeDefinition</code>s defined by the implementing class.<P>This
* is used by the {@link AbstractSecurityInterceptor} to perform startup time validation of each
* <code>ConfigAttribute</code> configured against it.</p>
*
* @return an iterator over all the <code>ConfigAttributeDefinition</code>s or <code>null</code> if unsupported
* @返回 ConfigAttributeDefinition迭代集合(Iterator)
*/
public Iterator getConfigAttributeDefinitions() {
Set set = new HashSet();
Iterator iter = this.getRdbmsEntryHolderList().iterator(); while (iter.hasNext()) {
RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
set.add(entryHolder.getCad());
} return set.iterator();
} /**
* 实现接口方法, 检验传入的安全对象是否是与FilterInvocation类相同类型, 或是它的子类
* getAttributes(Object object)方法会调用这个方法
* 保证String url = ((FilterInvocation) object).getRequestUrl();的正确性
*
* Indicates whether the <code>ObjectDefinitionSource</code> implementation is able to provide
* <code>ConfigAttributeDefinition</code>s for the indicated secure object type.
*
* @param clazz the class that is being queried
*
* @return true if the implementation can process the indicated class
*/
public boolean supports(Class clazz) {
if (FilterInvocation.class.isAssignableFrom(clazz)) {
return true;
} else {
return false;
}
} /**
* 覆盖JdbcDaoSupport中的方法, 用于将数据源传入RdbmsSecuredUrlDefinition中
* JdbcDaoSupport实现了InitializingBean接口, 该接口中的afterPropertiesSet()方法
* 用于在所有spring bean属性设置完毕后做一些初始化操作, BeanFactory会负责调用它
* 而在JdbcDaoSupport的实现中, afterPropertiesSet()方法调用了initDao()方法, 故我们
* 借此做一些初始化操作.
* 在此用于将数据源传入RdbmsSecuredUrlDefinition中
*/
protected void initDao() throws Exception {
logger.info("第一个执行的方法: initDao()");
this.rdbmsInvocationDefinition =
new RdbmsSecuredUrlDefinition(this.getDataSource()); // 传入数据源, 此数据源由Spring配置文件注入
if (this.webresdbCache == null)
throw new IllegalArgumentException("必须为RdbmsFilterInvocationDefinitionSource配置一EhCache缓存");
} /**
* 获取所有RdbmsEntryHolder列表(url与角色集合对应列表)
*
* @return
*/
private List getRdbmsEntryHolderList(){
List list = null;
Element element = this.webresdbCache.get("webres"); if (element != null){ // 如果缓存中存在RdbmsEntryHolder列表, 则直接获取返回
list = (List) element.getValue();
} else { // 如果缓存中不存在RdbmsEntryHolder列表, 则重新查询, 并放到缓存中
list = this.rdbmsInvocationDefinition.execute();
Element elem = new Element("webres", list);
this.webresdbCache.put(elem);
}
//list = this.rdbmsInvocationDefinition.execute();
return list;
} /**
* 用于Spring注入
*
* @param webresdbCache
*/
public void setWebresdbCache(Ehcache webresdbCache) {
this.webresdbCache = webresdbCache;
} }

由于RdbmsFilterInvocationDefinitionSource是针对Web资源的,因此它实现的supports()方法需要评估FilterInvocation对象。另外,为了减少同RDBMS的交互次数,我们启用了Spring EhCache服务。

 5、通过Spring DI注入RdbmsFilterInvocationDefinitionSource

  1. <bean id="filterInvocationInterceptor"
  2. class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  3. ......
  4. <property name="objectDefinitionSource"
  5. ref="rdbmsFilterInvocationDefinitionSource" />
  6. </bean>
  7. <bean id="rdbmsFilterInvocationDefinitionSource"
  8. class="sample.RdbmsFilterInvocationDefinitionSource">
  9. <property name="dataSource" ref="dataSource" />
  10. <property name="webresdbCache" ref="webresCacheBackend" />
  11. </bean>
  12. <bean id="webresCacheBackend"
  13. class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  14. <property name="cacheManager">
  15. <ref local="cacheManager" />
  16. </property>
  17. <property name="cacheName">
  18. <value>webresdbCache</value>
  19. </property>
  20. </bean>
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
......
<property name="objectDefinitionSource"
ref="rdbmsFilterInvocationDefinitionSource" />
</bean> <bean id="rdbmsFilterInvocationDefinitionSource"
class="sample.RdbmsFilterInvocationDefinitionSource">
<property name="dataSource" ref="dataSource" />
<property name="webresdbCache" ref="webresCacheBackend" />
</bean> <bean id="webresCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>webresdbCache</value>
</property>
</bean>

 6、运行说明
 下载源代码,我提供了相应脚本,存放在Acegi8WebRoot\rdbms目录下。
1)、在rdbms目录下运行server.bat文件,启动hsqldb数据库。关于hsqldb的使用说明,请参考“菜鸟-手把手教你把Acegi应用到实际项目中(6)” http://zhanjia.iteye.com/blog/258282
 2)、运行Acegi8项目
 3)、用户名为javaee、qiuzj,密码为password

至此,我们此节所讲的内容已结束,大家可以下载源代码以便调试。另外,代码中还提供了另一个版本的实现类RdbmsFilterInvocationDefinitionSourceVersion2,它继承了AbstractFilterInvocationDefinitionSource,在一定程序上减少了代码量,朋友们可以自行研究。

7、其他说明
开发环境:
MyEclipse 5.0GA
Eclipse3.2.1
JDK1.5.0_10
tomcat5.5.23
acegi-security-1.0.7
Spring2.0

Jar包:
acegi-security-1.0.7.jar
Spring.jar(2.0.8)
commons-codec.jar
jstl.jar (1.1)
standard.jar
commons-logging.jar(1.0)
hsqldb.jar(1.8.0.10)
log4j-1.2.13.jar
ehcache-1.3.0.jar

 更正注释, 红色部分为更改后的注释:

// 循环判断是否对当前url设置了安全角色访问机制, 有则返回相应的ConfigAttributeDefinition(角色集合), 否则返回null

  1. while (iter.hasNext()) {
  2. RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
  3. boolean matched = pathMatcher.match(entryHolder.getUrl(), url);
  4. if (logger.isDebugEnabled()) {
  5. logger.debug("匹配到如下URL: '" + url + ";模式为 "
  6. + entryHolder.getUrl() + ";是否被匹配:" + matched);
  7. }
  8. if (matched) {
  9. return entryHolder.getCad();
  10. }
  11. }
while (iter.hasNext()) {
RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) iter.next();
boolean matched = pathMatcher.match(entryHolder.getUrl(), url); if (logger.isDebugEnabled()) {
logger.debug("匹配到如下URL: '" + url + ";模式为 "
+ entryHolder.getUrl() + ";是否被匹配:" + matched);
} if (matched) {
return entryHolder.getCad();
}
}

菜鸟-教你把Acegi应用到实际项目(9)-实现FilterInvocationDefinition的更多相关文章

  1. 菜鸟-手把手教你把Acegi应用到实际项目中(10)-保护业务方法

    前面已经讲过关于保护Web资源的方式,其中包括直接在XML文件中配置和自定义实现FilterInvocationDefinitionSource接口两种方式.在实际企业应用中,保护Web资源显得非常重 ...

  2. 菜鸟-手把手教你把Acegi应用到实际项目中(8)-扩展UserDetailsService接口

    一个能为DaoAuthenticationProvider提供存取认证库的的类,它必须要实现UserDetailsService接口: public UserDetails loadUserByUse ...

  3. 菜鸟-手把手教你把Acegi应用到实际项目中(1.1)

    相信不少朋友们对于学习Acegi的过程是比较痛苦的,而且可能最初一个例子都没能真正运行起来.即使能运行起来,对于里面那么多的配置,更搞不清楚为什么要那么配,多配一个和少配一个究竟有什么区别? 最终头都 ...

  4. 菜鸟-手把手教你把Acegi应用到实际项目中(11)-切换用户

    在某些应用场合中,我们可能需要用到切换用户的功能,从而以另一用户的身份进行相关操作.这一点类似于在Linux系统中,用su命令切换到另一用户进行相关操作.      既然实际应用中有这种场合,那么我们 ...

  5. 菜鸟-手把手教你把Acegi应用到实际项目中(12)-Run-As认证服务

    有这样一些场合,系统用户必须以其他角色身份去操作某些资源.例如,用户A要访问资源B,而用户A拥有的角色为AUTH_USER,资源B访问的角色必须为AUTH_RUN_AS_DATE,那么此时就必须使用户 ...

  6. 菜鸟-手把手教你把Acegi应用到实际项目中(7)-缓存用户信息

    首先讲讲EhCache.在默认情况下,即在用户未提供自身配置文件ehcache.xml或ehcache-failsafe.xml时,EhCache会依据其自身Jar存档包含的ehcache-fails ...

  7. 菜鸟-手把手教你把Acegi应用到实际项目中(5)

    在实际企业应用中,用户密码一般都会进行加密处理,这样才能使企业应用更加安全.既然密码的加密如此之重要,那么Acegi(Spring Security)作为成熟的安全框架,当然也我们提供了相应的处理方式 ...

  8. 菜鸟-手把手教你把Acegi应用到实际项目中(4)

    今天就讲个ConcurrentSessionFilter. 在Acegi 1.x版本中,控制并发HttpSession和Remember-Me认证服务不能够同时启用,它们之间存在冲突问题,这是该版本的 ...

  9. 菜鸟-手把手教你把Acegi应用到实际项目中(6)

    在企业应用中,用户的用户名.密码和角色等信息一般存放在RDBMS(关系数据库)中.前面几节我们采用的是InMemoryDaoImpl,即基于内存的存放方式.这节我们将采用RDBMS存储用户信息. Us ...

随机推荐

  1. 运行ASP程序报错

    错误提示: An error occurred on the server when processing the URL. Please contact the system administrat ...

  2. [web] 200 OK (from cache) 与 304 Not Modified

    为什么有的缓存是 200 OK (from cache),有的缓存是 304 Not Modified 呢?很简单,看运维是否移除了 Entity Tag.移除了,就总是 200 OK (from c ...

  3. 用javacsv API 来操作csv文件

    javacsv是国外开发的一个比较好的操作csv文件的API,这里简单讲一下用法. 先下载javacsv2.0.zip的文件,解压后,把javacsv.jar 添加到项目中.  本站下载地址: htt ...

  4. scala vs java 相同点和差异

    本贴是我摘抄自国外网站,用作备忘,也作为分享! Similarities between Scala and Java Following are some of the major similari ...

  5. 遇到 Error creating the Web Proxy specified in the 'system.net/defaultProxy' configuration section的解决办法

    用记事本编辑*.EXE.config,在“<system.net>”节点加入<defaultProxy> <proxy usesystemdefault="Fa ...

  6. LintCode "Partition Array by Odd and Even"

    One pass in-place solution: all swaps. class Solution { public: /** * @param nums: a vector of integ ...

  7. 剑指offer系列34----按之字形顺序打印二叉树

    [题目]请实现一个函数按照之字形打印二叉树, * 即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印, * 其他行以此类推. 未优化,不是最优解,博主用的是队列 ...

  8. cent os下面的基本配置操作

    二,修改Linux分辨率命令行 在root用户模式下,输入$ vi /boot/grub/grub.conf(路径可能会不一样,也可以是 /etc/grub.conf),打开grub.conf文件 我 ...

  9. 242. Valid Anagram

    Given two strings s and t, write a function to determine if t is an anagram of s. For example,s = &q ...

  10. bug_ _ java.lang.IllegalArgumentException: pointerIndex out of range 问题的两种解决办法

    ========== 4     如何解决java.lang.IllegalArgumentException: pointerIndex out of range? 今天遇到一个bug:java.l ...