`
tuoxie007
  • 浏览: 160213 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

我设计的权限管理方案

    博客分类:
  • Java
阅读更多

这是给我们学校的某管理系统设计的一套权限管理子系统。今天把它总结一下,欢迎大牛过来踩。

权限系统的设计对于企业级项目来说极为重要,尤其是像我们的系统,数据很重要,要是成绩被人修改了,那就糟糕了。

其实权限控制无非是两方面:控制合适的人访问到合适的菜单,进入合适的菜单项之后可以访问到合适的数据。

我把系统设计的尽量简化,主要牵涉到以下几个对象。

一个是权限所有者Accessor,即访问者

      Accessor可以使一个用户,也可以是一个角色或是岗位,是什么只有客户程序知道。

 

一个是资源,Resource,表示可被访问的数据,

     为树形结构,每个资源为一个树的节点。客户程序可以自己控制资源的粒度。

 

一个是功能模块,Module,一个功能模块,或者是一个可访问的页面。

     由于这部分有其他人员开发,我的程序里面没有涉及到这个类,只是引用了这个类的ID。

 

一个是权限Authoritied,有三个外键,分别指向上面三个对象,其实就是一张三表关联的中间表。

 

针对以上所述,对程序敏感的你可能会提出以下问题:

1. Accessor可以是一个用户,也可以是一个角色或是岗位,那么如何表示一个访问者呢?

    我用了AccessorName这个字段,它是一个字符串类型,而且是不可重复的,由于我们的系统里表都有uuid,所以就把uuid放进来,作为AccessorName了。这里有一点,客户程序不只需用告诉我访问者的AccessorName是什么,并不需要知道这个Accessor是什么类型,所以这里的处理是可行的。

2. 这里的资源可以是各种类型,那么如何抽象的表示出各种类型的资源呢?

    这个问题和上面的类似,但处理方法不能一样,因为客户程序查询可访问资源列表之后需要知道资源的类型。处理的方法是,用Class类型的ResourceClass字段表示资源的类型,用ResourceId表示这个类型下的某个ID,通过这两个字段就可以确定资源是哪个具体的类型的实例了。

3. Authorited只是一张关联表,只能表示有没有访问的权限,不能表示权限的等级,比如读权限/写权限,那么如何控制权限等级呢?

     我是这么处理的,把菜单看做是一个功能模块,把菜单项看做是资源,而菜单细化到具体的功能,由于我们的系统里面每个页面的功能是相对单一的,没有把各种身份的功能做到一起,所以每一个菜单项就可以表示权限的等级了,比如查看成绩是一个菜单项,修改成绩是另外一个菜单项,这样只要控制这个人能否访问到指定页面就可以控制到权限等级。

 

 

以上是解决显示合适的菜单项的方案,当访问者进入合适的菜单项之后再查询可访问的资源列表,于是显示合适的数据。由于资源是树形结构,客户程序还可以查询某以某个资源实例为父资源的某种类型的资源,这样很容易控制数据的级联菜单形式的现实。

 

接下来就看一下我对外提供的操作接口方法是怎么样的吧。

 

public interface AclController {

	/**
	 * 查询权限,返回的资源列表中的每一项都递归的包含父资源直到Root
	 * @param accessor 访问者
	 * @param moduleId 访问的模块ID
	 * @return 可访问的资源列表
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public List<Resource> get(Accessor accessor, Long moduleId) throws AclDatabaseAccessException, AclAnnotationConfigurationException;

	/**
	 * 查询权限,返回的资源列表中的每一项都不包含父资源
	 * @param accessor 访问者
	 * @param moduleId 访问的模块ID
	 * @param parent 父资源
	 * @param resourceClazz 父资源Class对象
	 * @return
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public List<Resource> get(Accessor accessor, Long moduleId, Resource parent, Class resourceClazz) throws AclDatabaseAccessException, AclAnnotationConfigurationException;

	/**
	 * 修改一个权限
	 * @param oldAuthoritied
	 * @param newAuthoritied
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void modify(Authoritied oldAuthoritied, Authoritied newAuthoritied) throws AclDatabaseAccessException, AclAnnotationConfigurationException;

	/**
	 * 获取根资源
	 * @return
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public Resource getRootResource() throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	/**
	 * 增加一个资源
	 * @param resource
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void add(Resource resource) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	/**
	 * 删除一个资源
	 * @param resource
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void delete(Resource resource) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	/**
	 * 修改一个资源
	 * @param resource
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void modify(Resource resource) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	/**
	 * 增加一个权限主体
	 * @param accessor
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void add(Accessor accessor) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	
	/**
	 * 删除一个权限主体
	 * @param accessor
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void delete(Accessor accessor) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
	
	/**
	 * 修改一个权限主体
	 * @param accessor
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void modify(Accessor accessor) throws AclDatabaseAccessException, AclAnnotationConfigurationException;

	/**
	 * 添加一个权限
	 * @param authoritied
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void add(Authoritied authoritied) throws AclDatabaseAccessException, AclAnnotationConfigurationException;

	/**
	 * 删除一个资源
	 * @param authoritied
	 * @throws AclDatabaseAccessException
	 * @throws AclAnnotationConfigurationException
	 * @author xuke
	 */
	public void delete(Authoritied authoritied) throws AclDatabaseAccessException, AclAnnotationConfigurationException;
}

 其实权限系统主要是设计,至于如何实现都是小事情,简单说一下把,我的这个模块里是用spring做ioc的,数据库操作方面考虑到效率问题所以是用的jdbc,但模仿了hibernate的Annotation的配置方式,自己实现了表和字段的映射,所以sql是自动生成的,如果数据库改了,sql是不需要改的。

有兴趣的可以看看我的整个的代码,欢迎大牛给出宝贵意见,小弟先受了。

 

0
0
分享到:
评论
1 楼 metadmin 2009-06-15  
我是一直搞权限管理的,搞了4年多。欢迎试用我们的细粒度权限管理产品 www.metadmin.com。 有90天试用期。


也不敢说是大牛,就谈谈自己的看法吧。
1,从功能角度来看,如你所说,权限管理分为2种层次,a,功能控制;b,功能里面的资源控制。
2,从管理角度来看,分为2个方面。a, 最终用户需要管理的权限(比如分配角色、管理角色权限呀);b, 开发者需要管理的地方,开发者根据需求把客户提出的细粒度控制实现了。可以是硬coding,也可以是配置。

但不管采取那种手段,不要改变客户需要控制的部分。毕竟角色、用户、权限这种RBAC模型深入人心了。


权限控制可以分为2类:
1,查询数据的控制,这个IBM/ORACLE查询没有做,metadmin做了控制。查出当前用户具有权限查看的数据,而且要支持分页、自定义条件;
2,数据控制类,这个IBM/ORACLE有做,metadmin也做了。也就是判断当前用户对某条数据是否有操作权限,返回true/false。


我们产品现在做到,权限逻辑全部提取出来,而且不需要编码和xml配置,通过界面就能把权限配置出来,还可以在线测试。 有兴趣欢迎浏览 www.metadmin.com 有试用版,还有demo演示

相关推荐

Global site tag (gtag.js) - Google Analytics