学习Acegi应用到实际项目中(10)- 保护业务方法
前面已经讲过关于保护Web资源的方式,其中包括直接在XML文件中配置和自定义实现FilterInvocationDefinitionSource接口两种方式。在实际企业应用中,保护Web资源非常重要,它是保障Web应用安全性的关键部分。有了它,我们的Web应用就显得更加安全了。的确,部分Web应用有了它已经足够了。但许多时候却有这样的场景,某企业的系统允许用户A查看数据,但不允许他修改或删除数据;而用户B不但可以查看数据,而且可以修改和删除数据。此时,前面所说的保护Web资源的方式就无法满足这个需求了。既而我们会想到,关于查看、修改和删除等操作,都是通过操作相应业务方法来实现的。那么,我们可不可以实现对这些业务方法的保护呢?答案是肯定的,Acegi为我们提供了这一实现机制。
对于业务方法的保护,其实跟保护Web资源的方式非常相似。只要弄清楚了保护Web资源的工作原理和各种实现方式,再来学习保护业务方法相关的知识,那么很快上手。
在继续阅读本节内容之前,朋友们应该先阅读“学习Acegi应用到实际项目中(9)- 实现FilterInvocationDefinition”一节()。因为此篇的第二部分内容与前一篇的内容非常相似,故在此只列出不同部分,不做详细解释。
一、在Acegi配置文件中配置实现保护业务方法
1、下面先看看关于保护Web资源和保护业务方法的部分配置:
保护Web资源的配置
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager"
ref="httpRequestAccessDecisionManager" />
<property name="objectDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**/*.jpg=AUTH_ANONYMOUS,AUTH_USER
/**/*.gif=AUTH_ANONYMOUS,AUTH_USER
/**/*.png=AUTH_ANONYMOUS,AUTH_USER
/login.jsp*=AUTH_ANONYMOUS,AUTH_USER
/**=AUTH_USER
]]>
</value>
</property>
</bean>
保护业务方法配置
<bean id="contactManagerSecurity"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager"
ref="httpRequestAccessDecisionManager" />
<property name="objectDefinitionSource">
<value>
sample.service.IContactManager.create=AUTH_FUNC_ContactManager.create
sample.service.IContactManager.delete=AUTH_FUNC_ContactManager.delete
sample.service.IContactManager.getAll=AUTH_FUNC_ContactManager.getAll
sample.service.IContactManager.getById=AUTH_FUNC_ContactManager.getById
sample.service.IContactManager.update=AUTH_FUNC_ContactManager.update
</value>
</property>
</bean>
从上面配置方式可以看到,两种配置方式基本差不多,只有两个地方存在差别。一个是实现类不同,前者是FilterSecurityInterceptor,后者是MethodSecurityInterceptor。另外一个是objectDefinitionSource中的配置不同。
FilterSecurityInterceptor和MethodSecurityInterceptor都继承自AbstractSecurityInterceptor,而且都拥有objectDefinitionSource属性。尽管他们都拥有相同的objectDefinitionSource属性,但前者属于FilterInvocationDefinitionSource类型,而后者属于MethodDefinitionSource类型。然而,这两个Source又都继承自ObjectDefinitionSource。正因为如此,所以保护Web资源和保护业务方法的原理是一样的,只要懂得运用其中一个,那么另一个也就会了。
“=”号左边的内容代表了方法名全称,即以类的全限定名和目标方法名一同构成。“=”号右边的内容代表了左边方法所对应的角色集合,角色集合由逗号隔开的多个角色名构成。
2、业务接口和实现类
public interface IContactManager{
public List getAll();
public Contact getById(Integer id);
public void create(Contact contact);
public void update(Contact contact);
public void delete(Contact contact);
}
public class ContactManager implements IContactManager {
……
}
3、加入保护业务方法的拦截器
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributeSource">
<value>
sample.service.impl.ContactManager.*=PROPAGATION_REQUIRED
</value>
</property>
</bean> <!--dao start -->
<bean id="contactDao" class="sample.dao.impl.ContactDao">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean> <!--service start -->
<bean id="contactManagerTarget"
class="sample.service.impl.ContactManager">
<property name="contactDao">
<ref bean="contactDao" />
</property>
</bean> <bean id="contactManager"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>sample.service.IContactManager</value>
</property>
<property name="interceptorNames">
<list>
<idref local="transactionInterceptor" />
<strong><!-- 加入保护业务方法的拦截器 -->
<idref bean="contactManagerSecurity"/></strong>
<idref local="contactManagerTarget" />
</list>
</property>
</bean>
二、自定义实现MethodDefinitionSource接口保护业务方法
这部分内容建立在前一篇的基础之上,请参考:“学习Acegi应用到实际项目中(9)- 实现FilterInvocationDefinition”一节()
1、修改RdbmsEntryHolder类
前篇保护Web资源时RdbmsEntryHolder类如下:
public class RdbmsEntryHolder implements Serializable {
// 保护的URL模式
private String url;
// 要求的角色集合
private ConfigAttributeDefinition cad;
......
}
由于现在所要保护的是业务方法,故我们将url变量易名为method,这样会更加明确。method变量存放类似于“sample.service.IContactManager.create”、“sample.service.IContactManager.update*”的方法名全称
2、修改RdbmsSecuredUrlDefinition类
将RdbmsSecuredUrlDefinition改名为RdbmsSecuredMethodDefinition,黑体部分为修改后的代码。
public class RdbmsSecuredMethodDefinition extends MappingSqlQuery{
protected static final Log log = LogFactory.getLog(RdbmsSecuredMethodDefinition.class);
public RdbmsSecuredMethodDefinition(DataSource ds) {
super(ds, Constants.ACEGI_RDBMS_SECURED_SQL);
compile();
}
/**
* convert each row of the ResultSet into an object of the result type.
*/
protected Object mapRow(ResultSet rs, int rownum)
throws SQLException {
RdbmsEntryHolder rsh = new RdbmsEntryHolder();
// 设置业务方法
rsh.setMethod(rs.getString(Constants.ACEGI_RDBMS_SECURED_METHOD).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;
}
}
其中,Constants常量类如下:
public interface Constants {
// Acegi相关常量--------------------------------------------
// 业务方法与对应角色查询语句
public static final String ACEGI_RDBMS_SECURED_SQL =
"SELECT authority,protected_res FROM authorities WHERE auth_type='FUNCTION' AND authority LIKE 'AUTH_FUNC_ContactManager%'";
// 方法字段名称
public static final String ACEGI_RDBMS_SECURED_METHOD = "protected_res";
// 角色字符串字段名称
public static final String ACEGI_RDBMS_SECURED_ROLES = "authority";
}
3、自定义实现MethodDefinitionSource接口
修改RdbmsFilterInvocationDefinitionSource类,改名为RdbmsMethodDefinitionSource,并修改相应方法,黑体部分为修改后的代码。
变量:
修改前:private RdbmsSecuredUrlDefinition rdbmsInvocationDefinition;
修改后:private RdbmsSecuredMethodDefinition rdbmsSecuredMethodDefinition;
以下两个函数,黑体为修改或增加部分:
protected void initDao() throws Exception {
this.rdbmsSecuredMethodDefinition =
new RdbmsSecuredMethodDefinition(this.getDataSource()); // 传入数据源, 此数据源由Spring配置文件注入
……
}
public ConfigAttributeDefinition getAttributes(Object object) throws IllegalArgumentException {
if ((object == null) || !this.supports(object.getClass())) {
throw new IllegalArgumentException("抱歉,目标对象不是MethodInvocation类型");
}
Method method = ((MethodInvocation) object).getMethod();
List list = this.getRdbmsEntryHolderList();
if (list == null || list.size() == 0)
return null;
// 获取方法全称, 如java.util.Set.isEmpty
String methodString = method.getDeclaringClass().getName() + "." + method.getName();
String mappedName;
Iterator it = list.iterator();
// 循环判断当前访问的方法是否设置了角色访问机制, 有则返回ConfigAttributeDefinition(角色集合), 否则返回null
while (it.hasNext()) {
RdbmsEntryHolder entryHolder = (RdbmsEntryHolder) it.next();
mappedName = entryHolder.getMethod();
boolean matched = pathMatcher.match(entryHolder.getMethod(), methodString);
//boolean matched = methodString.equals(mappedName) || isMatch(methodString, mappedName);
if (logger.isDebugEnabled()) {
logger.debug("匹配到如下Method: '" + methodString + ";模式为 "
+ entryHolder.getMethod() + ";是否被匹配:" + matched);
}
// 如果在用户所有被授权的URL中能找到匹配的, 则返回该ConfigAttributeDefinition(角色集合)
if (matched) {
return entryHolder.getCad();
}
}
return null;
}
4、通过Spring DI注入RdbmsMethodDefinitionSource
<bean id="contactManagerSecurity"
class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager" />
<property name="objectDefinitionSource" ref="<strong>rdbmsMethodDefinitionSource</strong>" />
</bean> <bean id="<strong>rdbmsMethodDefinitionSource</strong>" class="sample.service.impl.<strong>RdbmsMethodDefinitionSource</strong>">
<property name="dataSource" ref="dataSource" />
<property name="webresdbCache" ref="webresCacheBackend" />
</bean> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> <bean id="webresCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager"/>
</property>
<property name="cacheName">
<value>webresdbCache</value>
</property>
</bean>
至此,此节所讲的内容已结束。
学习Acegi应用到实际项目中(10)- 保护业务方法的更多相关文章
- 菜鸟-手把手教你把Acegi应用到实际项目中(10)-保护业务方法
前面已经讲过关于保护Web资源的方式,其中包括直接在XML文件中配置和自定义实现FilterInvocationDefinitionSource接口两种方式.在实际企业应用中,保护Web资源显得非常重 ...
- 学习Acegi应用到实际项目中(2)
Acegi应用到实际项目中(1)是基于BasicProcessingFilter的基本认证,这篇改用AuthenticationProcessingFilter基于表单的认证方式. 1.authent ...
- 学习Acegi应用到实际项目中(7)- 缓存用户信息
在默认情况下,即在用户未提供自身配置文件ehcache.xml或ehcache-failsafe.xml时,EhCache会依据其自身Jar存档包含的ehcache-failsafe.xml文件所定制 ...
- 学习Acegi应用到实际项目中(1)
在此,本人声明,我处于菜鸟阶段,文章的内容大部分摘自zhanjia的博客(http://zhanjia.iteye.com/category/43399),旨在学习,有很多地方,我理解不够透彻,可能存 ...
- 学习Acegi应用到实际项目中(12)- Run-As认证服务
有这样一些场合,系统用户必须以其他角色身份去操作某些资源.例如,用户A要访问资源B,而用户A拥有的角色为AUTH_USER,资源B访问的角色必须为AUTH_RUN_AS_DATE,那么此时就必须使用户 ...
- 学习Acegi应用到实际项目中(11)- 切换用户
在某些应用场合中,可能需要用到切换用户的功能,从而以另一用户的身份进行相关操作.这一点类似于在Linux系统中,用su命令切换到另一用户进行相关操作. 既然实际应用中有这种场合,那么我们就有必要对其进 ...
- 学习Acegi应用到实际项目中(9)- 实现FilterInvocationDefinition
在实际应用中,开发者有时需要将Web资源授权信息(角色与授权资源之间的定义)存放在RDBMS中,以便更好的管理.事实上,一般的企业应用都应当如此,因为这样可以使角色和Web资源的管理更灵活,更自由.那 ...
- 学习Acegi应用到实际项目中(8)- 扩展UserDetailsService接口
一个能为DaoAuthenticationProvider提供存取认证库的的类,它必须要实现UserDetailsService接口: public UserDetails loadUserByUse ...
- 学习Acegi应用到实际项目中(5)
实际企业应用中,用户密码一般都会进行加密处理,这样才能使企业应用更加安全.既然密码的加密如此之重要,那么Acegi(Spring Security)作为成熟的安全框架,当然也我们提供了相应的处理方式. ...
随机推荐
- kruskal(拓展)
kruskal是最小生成树的一种做法,即严格按照贪心思想将边从小到大排序,一个一个枚举能不能加入图中,知道生成一棵树,显然树为最小树. 鄙人觉得kruskal做法远不止如此,那种严格从小到大选边的做法 ...
- bash小技巧1 获取文件当前路径
我们linux获取文件当前路径一般问 #逼格不够高 [root@xxxx]# pwd 高逼格 SHELL_FOLDER=$(dirname $(readlink -f "$0"))
- dubbo常见面试问题(二)
1.什么是Dubbo? Duubbo是一个RPC远程调用框架, 分布式服务治理框架 2.什么是Dubbo服务治理? 服务与服务之间会有很多个Url.依赖关系.负载均衡.容错.自动注册服务 3.Dubb ...
- cdnbest常见问题
1.cdn配置了ssl证书,经常有用户说访问不了,如果cdn配置了ssl,源没有配置ssl,在cdn里添加源ip的写法: 如果源也配置了ssl证书,写法如下图: 2. cdn报504问题的原因: 50 ...
- Java框架spring 学习笔记(七):Spring相关概念
Spring是开源.轻量级.一站式框架. Spring核心主要两部分 aop:面向切面编程,扩展功能不是修改源代码实现. ioc:控制反转,把对象的创建交给Spring进行配置,比如一个类,在类里面有 ...
- 搞搞电脑微信表情的破解(.dat转png or jpg)
首先感谢:https://blog.csdn.net/weixin_42440768/ 因为狗子喜欢之前那个头像,但是没找到,于是我想看看我们之前的斗图过程中有没有发她的头像. 这是做这件事情的起因. ...
- HDU - 1695 GDU
莫比乌斯反演基础. 用rep 去掉重复的对数,rep一定是奇数( 因为有(1,1 ) ) #include <bits/stdc++.h> using namespace std; #de ...
- PCIE错误分析
前面的文章提到过,PCI总线中定义两个边带信号(PERR#和SERR#)来处理总线错误.其中PERR#主要对应的是普通数据奇偶校检错误(Parity Error),而SERR#主要对应的是系统错误(S ...
- python 基础 ----- 常用的方法
one.将英文字符设置大小写 upper() :将英文字符设置大写 lower() :将英文字符设置小写 two.去掉字符串的首尾空格 不能去除字符串中间的空格偶 strip() : 去掉 ...
- formValidator 插件 使用总结
1. 大小写的问题, formvalidator 的属性 大小写问题一定要注意, 在踩过的坑里就包括这个, 把所有属性的第二个字母的开头全部写成大写 ,导致提示信息不能用,这个问题纠结了好久 2.er ...