我设计的权限管理方案
这是给我们学校的某管理系统设计的一套权限管理子系统。今天把它总结一下,欢迎大牛过来踩。
权限系统的设计对于企业级项目来说极为重要,尤其是像我们的系统,数据很重要,要是成绩被人修改了,那就糟糕了。
其实权限控制无非是两方面:控制合适的人访问到合适的菜单,进入合适的菜单项之后可以访问到合适的数据。
我把系统设计的尽量简化,主要牵涉到以下几个对象。
一个是权限所有者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是不需要改的。
有兴趣的可以看看我的整个的代码,欢迎大牛给出宝贵意见,小弟先受了。
?
1 楼 metadmin 2009-06-15 我是一直搞权限管理的,搞了4年多。欢迎试用我们的细粒度权限管理产品 www.metadmin.com。 有90天试用期。