前言:权限设计是一个80%的程序员都会遇到的问题,比如应用系统权限,数据库的访问权限,公文流转中的审批权限,操作系统中文件的访问权限,公司内部单据的审批权限,政府机构的上下级权限等,在现实生活中,权限无处不在,无时不有。这里要介绍的是关于文档的访问权限的一种设计方案,供大家讨论,希望能起到抛砖引玉的作用。
       在公司内部,合同文件,针对某一个客户的设计草案等一系列物理的文件,组成了一个逻辑上的文档,典型的如应用系统设计中数据库设计ER图、类图、对象图等一系列的文件,在逻辑上可以称之为一个应用系统的设计文档。当类似的文档超过几百个之后,公司内部文档的管理依靠建立纸质的文档卡片来检索文件便显得比较慢了,这时一个在线的文档管理系统就成为公司这个阶段的需求,用于解决文档过多带来的诸多不便。
       在线文档管理系统的主要目标就是方便用户管理文档和互相交流,但并不是每个人都可以对任何文档查看或者修改。权限管理在这里便成为举足轻重的问题:那些是我的文档,同部门的同事对我的文档具有哪些权限,其他人对我的文档有哪些权限,其他部门的人对我的文档有什么权限,是否可以有一个特定的人或者特定的部门对我的文档有特定的权限。本文针对这些问题提供一个解决方案,其中一些必须的元素比如,用户的设计,部门的设计不在本文讨论之列,假设您已经设计的比较完善。笔者借鉴UNIX的一些权限设计的思想来讨论和解决这些问题。分两部分:
第一部分讨论权限的种类:针对每个文档,需要填写以下文档信息,比如文档的名称,作者等,之后添加附件。对于文档的操作固定分为4种:下载,删除,修改,查看。比如需要下载某个文件,就需要具备下载权限,但首先要具备查看的权限,如果没有查看权限,则就无从下载,如果需要修改某些信息,包括重新上传文件,则需要具备修改的权限。这4中权限可以使用四个位来代替,1代表有权限,0带便没有权限,比如第一个位为下载,第二个为删除,第三个位为修改,第四个位为查看,则1111就具备了所有的权限,0000则表示没有任何权限,这样的二进制位便可以以16进制的方式存储在数据库中比如使用0..A..F则在数据库中的存储只为一个字节。如果需要添加权限,那么在高位添加这个权限。Java中的Integer类中可以方便的进行移位操作,针对给出的权限的二进制位,在相应位进行&操作,判断结果是否大于0就知道是否有权限,比如10100010进行&操作,如果结果大于0,则说明有修改的权限。如果需要增加权限,则把原来的权限取出来,在相应的权限位进行或|运算,之后再存进去。这点和Unix的权限设计一致。
第二部分讨论如何授权,假设用户具备一个唯一的×××ID号,每个部门具备一个×××ID号,对于具有1000人的公司来说,部门有上百个,他们的平均ID号的长度可以假设为3位。在文档的记录中需要添加一个字段填写文档拥有者的编号(owner),以便于标示这个文档属于谁的。同时也添加拥有者所在的部门编号(dept),如果同一个人曾经在两个部门工作过,那么他在不同时期的文档应该属于不同的部门。在这些之后需要有一个文档拥有者的权限字段(ownerAuth),存储1个字节的权限信息(假设只有四种权限)。同部门的人经常需要查看,或者修改等操作,为了方便检索需要添加同部门权限(deptAuth),同样是1个字节,也要有其他任何人对该文档的权限(otherAuth),假设是一个通知,或者文档的模板,需要所有人具备读权限,使用这个方式就比较合适。如果需要对某个人授权怎么办?如果对某个部门单独授权怎么办?这里有两种方案,1.添加一个表,与文档表是多对一的关系,这样就可以把一个文档授权给多个部门,或者多个人。2.添加两个字段,usersAuth,deptsAuth,注意,auth之前有个s,表示存储多个人或者部门的权限。存储的内容为ID号加权限,比如usersAuth中的100:f101:A,表示ID号为100的用户有用F所有的权限,以此类推,可知为单个人或者部门授权需要6个字节,1k个字段长度已经可以对170多个对象单独授权,这基本上是一个操作人员的极限,操作人员不会闲的无聊把一个对象逐个的授权给170个人或者部门,属于小概率事件,实际中可以忽略不计。这两种方案中,作者偏向于第二种,优点是查询次数少,其缺点是授权对象个数有限制。如何判断一个用户对某一个文档是否有特定的权限,在这里可以根据自己的使用情况定一个优先查找顺序,比如要判断用户对文档A是否有读的权限,则可以从ownerAuth->groupAuth->otherAuth->usersAuth->deptsAuth的优先顺序查找判断,也可以按照自己的方案判断,对于otherAuth比较常用的文档系统,把otherAuth的权限判断放在第一位也许更合适。这个没有统一的准则。
以上是作者对文档权限设计的一点想法,时间仓促,没有仔细琢磨语句是否通畅,如果有说的不清楚的地方或者有不正确的地方,欢迎指教。