`
popufig
  • 浏览: 5134 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

由django的Authentication想到RBAC permission实现(Struts版)

    博客分类:
  • Java
阅读更多

先简单的说一下RBAC的概念:

主要有user, role 和 permission 这么三个元素,用户可以有多个角色,角色可以有多个 permission,这里的permission可以理解成对resource+operation。在这个基础上还可以增加group的概念,相信不难理解。

 

假设系统对于权限的要求是:能控制系统动态菜单的访问,控制其它的提交操作。

以下的想法是基于struts 1.2 + java 1.4 (部门最近一直比较保守,晕死)

 

个人觉得要实现这个模型的难点在于permission, 也就是其中的resource,应用中的资源应该包括动态资源和静态资源两类:

  • 动态资源:比如说用户上传的文档,不同的文档可能会给不同的角色分配不同的权限。
  • 静态资源:某些地方系统只要求控制固定的表单哪些角色可以查看,哪些角色可以更新。

个人认为动态资源相对比较容易处理,因为我们把这个动态资源的ID作为resource的ID,然后再加入一个resource type的属性就可以处理多种资源了。为什么说动态资源比较容易处理呢,因为我们处理这些动态资源的时候都是以ID来操作的,查询的时候也可以用ID进行过滤,唯一需要注意的可能会是性能问题,可以考虑使用缓存。

 

静态资源就有点麻烦了,说白了,其实控制静态资源就是控制角色是否可以访问系统中的某个方法。那么这时候我们怎么在permission里标识这个操作呢?有人会说,用URL,偶承认,这个绝对可以控制,但是这么做的话也就意味着权限是无法交给真正的用户来维护,除非你愿意维护一个URL与用户能看懂文字的对应列表,有点麻烦,也很难检查有没有遗漏的。

 

我想的办法是在自己的BaseFom(一般用struts的多少都会有这个东东)中加入一些代码:

public BaseForm extends .... {
...

    public static final String CREATE = "create";
    public static final String REVIEW = "view";
    public static final String UPDATE = "update";
    public static final String DELETE = "delete";

    private List operations = new ArrayList();

    //用于获取对用户友好的表单名称
    public String getFormName() {
        return "";
    }

    public List getOperations() {
         //map中的value也是考虑用户友好
         operations.add(new HashMap().put(CREATE, "Add new record"));
         operations.add(new HashMap().put(REVIEW, "Search and view the records"));
         operations.add(new HashMap().put(UPDATE, "Update the record"));
         operations.add(new HashMap().put(DELETE, "Delete the record"));

         return operations;
    }

...
}

 

接下来假设说我们有一个针对项目的新增/删除/修改/查询以及失效 操作,先来写我们的form:

public class ProjectForm extends BaseForm {

    private static final String FORMNAME = "Project Information";
    public static final String INVALID = "invalid";

    public String getFormName() {
        return FORMNAME;
    }

    public List getOperations() {
        List operations = supper.getOperations();
        operations.add(new HashMap().put(INVALID, "Set project as invalid"));
        return operations;
    }
...
}

 

再来看看action怎么写:

public ProjectAction extends ... {

    //创建项目,其它的方法类似
    public ActionForward createProject(....) {
        //从session中获取用户信息
        User user = ....;

        //假设我们有一个类专门处理权限检查
        PermissionChecker checker = new PermissionChecker();
        checker.setResource(form.getFormName());
        checker.check(user, ProjectForm.CREATE);
    }
}

 

上面action中的方法比较丑陋, 其实如果是JDK 5的话就可以用annotation解决就比较优雅了,而且上面的代码还可以进一步重构。

 

个人认为这么做相对URL的控制有几个好处:

  1. 很容易就检查到方法是否控制到;
  2. 方法名的修改不影响用户的配置;
  3. 在一个地方配置整个系统的URL很容易让人晕菜;
  4. 不同的模块可以分开指定有哪些需要的操作,比如说其它的模块还需要发布、撤销等操作;

其不足之处就是代码量有所增加,action的方法还需要自己调用一些API,如果用URL控制就可以用filter了。

 

系统部署后也可以遍历所有配置的form,根据现有的信息就可以配置出想要的permission并授权给角色。

 

写了半天没提到一点django,呵呵,其实django中自带的 Authentication 模块就是类似的做法,模块自带了CRUD的操作,用户可以在写自己的model的时候增加定制的操作,有兴趣的朋友可以参考这里: http://docs.djangoproject.com/en/dev/topics/auth/#topics-auth

 

想法是今天回家的路上想的,肯定有很多没考虑到的地方,不知道这种方式是否实际可操作,随后也打算学习一些acegi的原理。

 

2
1
分享到:
评论
1 楼 grandboy 2010-01-28  
请问一下, 这个思想在实际项目里,有没有改进? 看起来这个文章发布的比较早了,现在有没有新的思想加进来?

相关推荐

Global site tag (gtag.js) - Google Analytics