首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

初学者-手把手教你把Acegi应用到实际项目中(10)-保护业务方法

2012-11-03 
菜鸟-手把手教你把Acegi应用到实际项目中(10)-保护业务方法????? 前面已经讲过关于保护Web资源的方式,其中

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

????? 前面已经讲过关于保护Web资源的方式,其中包括直接在XML文件中配置和自定义实现FilterInvocationDefinitionSource接口两种方式。在实际企业应用中,保护Web资源显得非常重要,它是保障Web应用安全性的关键部分。有了它,我们的Web应用就显得更加安全了。的确,部分Web应用有了它已经足够了。但许多时候却有这样的场景,某企业的系统允许用户A查看数据,但不允许他修改或删除数据;而用户B不但可以查看数据,而且可以修改和删除数据。此时,前面所说的保护Web资源的方式就无法满足这个需求了。既而我们会想到,关于查看、修改和删除等操作,都是通过操作相应业务方法来实现的。那么,我们可不可以实现对这些业务方法的保护呢?答案是肯定的,Acegi为我们提供了这一实现机制。
????? 对于业务方法的保护,其实跟保护Web资源的方式非常相似。只要我们弄清楚了保护Web资源的工作原理和各种实现方式,再来学习保护业务方法相关的知识,那么将会很快上手。
????? 在继续阅读本节内容之前,朋友们应该先阅读“菜鸟-教你把Acegi应用到实际项目(9)-实现FilterInvocationDefinition”一节(http://zhanjia.iteye.com/blog/261123)。因为此篇的第二部分内容与前一篇的内容非常相似,故在此我只列出不同部分,不做详细解释。

一、在Acegi配置文件中配置实现保护业务方法
1、下面先看看关于保护Web资源和保护业务方法的部分配置:
*保护Web资源的配置

?

<bean id="filterInvocationInterceptor"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"ref="authenticationManager" /><property name="accessDecisionManager"ref="httpRequestAccessDecisionManager" /><property name="objectDefinitionSource"><value>sample.service.IContactManager.create=AUTH_FUNC_ContactManager.createsample.service.IContactManager.delete=AUTH_FUNC_ContactManager.deletesample.service.IContactManager.getAll=AUTH_FUNC_ContactManager.getAllsample.service.IContactManager.getById=AUTH_FUNC_ContactManager.getByIdsample.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"/></property><property name="transactionAttributeSource"><value>sample.service.impl.ContactManager.*=PROPAGATION_REQUIRED</value></property></bean><!--dao start --><bean id="contactDao" /></property></bean><!--service start --><bean id="contactManagerTarget"/></property></bean><bean id="contactManager"/><!-- 加入保护业务方法的拦截器 --><idref bean="contactManagerSecurity"/><idref local="contactManagerTarget" /></list></property></bean>

?

?

?二、自定义实现MethodDefinitionSource接口保护业务方法
????? 这部分内容建立在前一篇的基础之上,请参考:“菜鸟-教你把Acegi应用到实际项目(9)-实现FilterInvocationDefinition”一节(http://zhanjia.iteye.com/blog/261123)

?

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.isEmptyString methodString = method.getDeclaringClass().getName() + "." + method.getName();String mappedName;Iterator it = list.iterator();// 循环判断当前访问的方法是否设置了角色访问机制, 有则返回ConfigAttributeDefinition(角色集合), 否则返回nullwhile (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" ref="authenticationManager" /><property name="accessDecisionManager" ref="httpRequestAccessDecisionManager" /><property name="objectDefinitionSource" ref="rdbmsMethodDefinitionSource" /></bean><bean id="rdbmsMethodDefinitionSource" ref="dataSource" /><property name="webresdbCache" ref="webresCacheBackend" /></bean><bean id="cacheManager" /> <!--service start -->  <bean id="contactManagerTarget"      />      </property>  </bean>    <bean id="contactManager"      />              <STRONG><!-- 加入保护业务方法的拦截器 -->              <idref bean="contactManagerSecurity"/></STRONG>              <idref local="contactManagerTarget" />          </list>      </property>  </bean> 


请问,如果我Struts2 Action被spring ioc了。 这时候只有类没有接口 。

应该如何写这里 :

    <property name="proxyInterfaces">          <value>sample.service.IContactManager</value>      </property>  

热点排行