基于组件方法级别授权访问

板桥里人 http://www.jdon.com 2005/10/29(转载请保留)

  当用户登陆进入系统后,面临着其访问权限的检查,目前实际应用中,授权访问(ACL)一般有以下几种:

  • 1. Web资源,主要是以Web URL为特征,对Web资源的Jsp/Servlet 图片等目录下全部资源实现授权访问。
  • 2. 组件资源,同一个组件的不同方法实现对资源进行不同性质的操作,每种操作方法都需要实现授权访问,例如:A角色可以实现帖子创建,但不能实现帖子删除。
  • 3. 数据资源,保存在数据库中的某些数据只能让特定角色一些访问。比如某个帖子只能让积分超过多少的用户访问。

  其中Web资源的ACL实现有很多种,使用基于Web容器的安全验证或使用开源项目JGuard。Web资源的ACL的有一个特点,它只能对Web资源实现授权访问,如果你设置/auth目录下的资源只能被某些角色访问,也就是说网址http://localhost/myweb/auth/下包括图片等任何资源只能被指定角色访问,这样,对Web资源形成了有效的保护。

  假设你有一个组件服务,如TestService如下:

public interface TestService {
  public UserTest initUser();

  public void createUser(EventModel em);

  public void updateUser(EventModel em);

  public void deleteUser(EventModel em);

  public UserTest getUser(String userId);

  public PageIterator getAllUsers(int start, int count);
}

  如果你授权目录和未授权目录都有对TestService访问,如下面struts-config.xml

<action name="userActionForm" path="/userSaveAction"   type="com.jdon.strutsutil.ModelSaveAction"
  scope="request" validate="true" input="/user.jsp">
  <forward name="success" path="/result.jsp" />
  <forward name="failure" path="/result.jsp" />
</action>



<action name="userActionForm" path="/auth/userSaveAction"   type="com.jdon.strutsutil.ModelSaveAction"
  scope="request" validate="true" input="/auth/user.jsp">
  <forward name="success" path="/auth/result.jsp" />
  <forward name="failure" path="/auth/result.jsp" />
</action>

  也就是说,网址http://localhost/myweb/userSaveAction.do与http://localhost/myweb/auth/userSaveAction.do

  都是实现用户资料的保存,都将分别调用TestService的createUser和updateUser等方法。如下:

  如果你的设计目的是:用户的创建可以开放给任何人,但是用户资料的修改或删除只能由超级管理员Admin实施,其他任何人员都没有权限进行修改或删除。

  为了实施这个设计目的,如果只使用 Web资源的ACL,使用如上图设计,将存在安全隐患,因为http://localhost/myweb/userSaveAction.do是完全开放给任何人,任何人对将从这个入口实现对TestService的访问,这样系统容易留有安全漏洞。

  一个解决方案是将用户资料的修改或删除功能从TestService接口中分离出来,这是破坏了对象的封装性。

  根本解决之道是使用基于组件方法的ACL,也就是前面总结的第2条,下面我们谈谈在Jdon框架下如何实现这个功能。

  实现组件TestService的第一步思路是在其createUser和updateUser等方法中加入权限判断,这种方式缺点是将权限和业务逻辑(如数据库操作)混淆的在一起,授权在发生变化时,修改createUser方法有可能更改业务逻辑代码,造成很大的不安全性。很显然,ACL和业务逻辑必须分开。

  分离的方法首先使用设计模式,这里可以选用Decorator模式或Proxy模式,所以我们需要实现TestService接口的一个子类TestServiceProxy,在TestServiceProxy中的各个方法中进行权限检查,而原来的TestService子类实现TestServiceImp则完全封装的是是业务逻辑。jive就是采取这个实现原理的。

  但是这样做哟一个缺点,每个接口都要实现一个Proxy类,如果有很多服务接口,需要实现很多Proxy类,这些Proxy类数量多而庞杂,系统不简练。

  比较好的解决办法是使用拦截器概念来实现,也就是我们只要做一个通用的Proxy类,系统能够在运行时自动检查。

  使用Jdon框架可以很方便地实现这个目的,因为Jdon框架的组件都是可插拔,可配置的,因此只要我们编制一个权限拦截器插入Jdon框架,然后使用XML配置文件描述一下哪些方法只能被哪些角色访问,权限拦截器根据这个配置规则进行运行检验,这样既做到分离,又达到简洁的效果。

  首先,我们使用XML定义ACL的访问规则,这个规则XML可以由我们任意指定,因为是我们自己写XML解析器解析它,我把它设定如下格式:

<permission>

  <service ref="testService">
    <method name="createUser">
      <role>Admin</role>
    </method>
    <method name="updateUser">
      <role>Admin</role>
      <role>User</role>
    </method>
    <method name="deleteUser">
      <role>Admin</role>
    </method>
  </service>

</permission>

  在这个配置中,我们定义了TestService的createUser方法只能被Admin访问,而updateUser的方法只能被Admin和user访问。

  然后,我们自己做一个XML解析器解析它,使用Jdon框架辅助的Jdom读取XML很方便,拷贝框架内其他读取XML代码即可,这个类在本文附件源码包中的PermissionXmlParser。

  最后,我们编制一个拦截器,主要代码如下:

public class PermissionInterceptor implements MethodInterceptor {
....

  public Object invoke(MethodInvocation invocation) throws Throwable {
    logger.debug("enter PermissionInterceptor");
    ....

    boolean hasPerm = false;

    Method method = invocation.getMethod();
    String methodNameNow = method.getName(); //获取当前被访问服务的方法名
    String serviceName = targetMetaDef.getName();//获取当前被访问服务的名称

    if (!isAuth(serviceName, methodNameNow)){ //如果在XML中没有定义,放行
      return invocation.proceed();
    }
    try {
      TargetMetaRequest targetMetaRequest =           proxyMethodInvocation.getTargetMetaRequest();

      //获得Jdon框架的SessionContext,这个类似HttpSession
      //通过SessionContext可以在微容器框架内部使用Session类数据
      SessionContext sessionContext = targetMetaRequest.getSessionContext();

      //获得登陆用户名,下行类似request.getPrincipleName()方法
      //通过下行,可以在微容器框架内部获得基于Web容器登陆用户的Principle Name
      String principleName =             userPrincipalSetup.getPrincipalName(sessionContext);
      logger.debug("principleName=" + principleName);

      //使用SessionContext作为缓存,不必每次根据Principle Name查询角色时,
      //都会访问数据库
       String roleName = (String)sessionContext.getArrtibute("roleName");
      if (roleName == null){
            roleName = operatorDao.getOperator(principleName);
            sessionContext.setArrtibute("roleName", roleName);
      }

      //从XML配置中检查当前服务和方法以及角色是否在配置中,也就是是否有权限。
      hasPerm = isUserInRole(serviceName, methodNameNow, roleName);
    } catch (Exception e) {
      logger.error(e);
    }

    if (hasPerm)
      return invocation.proceed();
    else {
      logger.error("no permission operate method: " + methodNameNow + " for "
             + targetMetaDef.getClassName());
    throw new Throwable("no permission");//这里可以抛出一个无权限的Exception!
  }
}

.....

}

  当然为了使这个拦截器能够被Jdon框架装载,有两个方法:一个是更改jdonframework.jar包中META-INF目录下的aspect.xml,将PermissionInterceptor放入;或者在自己项目下建立一个文件myaspect.xml,在其中配置如下:

<aspect>

  <interceptor name="test_permissionInterceptor"       class="com.jdon.framework.test.service.PermissionInterceptor"       pointcut="pojoServices" />

</aspect>

  只要确保myaspect.xml在WEB-INF/classes下,Jdon框架就会自动装载,当然因为PermissionInterceptor使用到XML解析,还需要在jdonframework.xml配置解析器PermissionXmlParser如下:

<pojoService name="testService"   class="com.jdon.framework.test.service.TestServicePOJOImp"/>


<pojoService name="operatorDao" class="com.jdon.framework.test.dao.OperatorDao" >
  <constructor value="java:/NewsDS"/>
</pojoService>

<pojoService name="permissionXmlParser"   class="com.jdon.framework.test.service.PermissionXmlParser" >
  <constructor value="test_permission.xml"/>
</pojoService>

  其中test_permission.xml就是前面的权限定义XML配置文件。

  注意,上述使用Jdon框架上述基于组件方法的ACL前提是,必须首先获得验证合格的登陆用户信息,本例子中登陆系统是使用基于Web容器的登陆方法。

  本例子源码按这里PermissionTest.rar下载,注意本例子中web.xml和jbos-web.xml配置,其中使用了基于JBoss的Web容器的登陆系统,这方面的JBoss的配置和数据库参考JdonNews

  该功能必须使用Jdon Framework 1.3版本。

  发布讨论

更多Jdon框架专题讨论

JdonFramework作为一个免费开源软件开发平台,可以商用开发大多数数据库应用软件和管理软件: 电子商务软件 在线教育软件 税务软件 Web快速开发软件 财务软件 购物车软件 医院帐务软件 crm software medical software 人事薪资软件payroll software 在线购物软件 销售软件 项目管理软件 房产不动产管理软件 生产软件 PDM软件 制造业软件 仓库软件 采购软件 进销存软件 危险源监控软件 物流软件 超市软件 银行软件 保险软件 汽车软件 医疗软件 电子软件 自动化软件 服装软件 烟草软件 分销管理软件 供应商管理软件

下载源码

框架文档

框架应用系统

演示运行

JiveJdon3

性能测试

Q&A 问答

技术支持

 

 

标签总列表



Jdon框架演示

JiveJdon3.0
源码下载

GoF设计模式

在线教程

社区精彩讨论




google yahoo 新浪ViVi 365Key网摘 天极网摘 CSDN网摘 添加到百度搜藏 POCO网摘






手机阅读 add to google add to yahoo
联系我们 | 关于我们 | RSS订阅 | 广告联系 | 网站地图 | 设为首页
Copyright (C) 2002-2009 Jdon.com, All Rights Reserved 版权所有 上海解道计算机技术有限公司
沪ICP备05018152号 如有意见请与我们联系 Powered by JdonFramework