2007-07-24
网站多用户权限管理的一个解决方案
看了discuz后台的用户权限设定,很详细,觉得很不错,就想自己要是能做出来就好了。
绞尽脑汁想出来一点,拿出来给高手看看,抛砖引玉,希望高手们能提出更好的方案,让大家以后权限管理的时候更轻松些。思考过程就不说了,没什么理论性的东西,无非是想想平时接触的操作系统,软家等的权限管理方式,再“灵光一闪”就得到了结果。
通过URL匹配控制访问权限,也就是在用户请求某个URL的时候,查看该用户是否有这个权限。这个“查看”是在一个Filter中进行的。判断用户是否有权限的标准是在一个xml文件中配置的。Dtd文档如下
Xml文档的核心是mapping元素,有url,code属性(必选)和error,message子元素。url表示匹配的URL,code是权限码,当用户的权限码符合这里的配置的权限码时,就认为用户用权限访问该URL,name属性唯一表示一个mapping。allmapping元素是的内容所有mapping元素name的集合,每个name之间用一个符号隔开,比如’|’或’,’都可以,用来帮助自动生成权限码,后面详细说明。Error(可选,如果没有则使用globe-error)是用户无权限时显示的错误页面,redirect属性(可选)制定forward到错误页面还是redirect到forward页面。message指定返回的错误信息(支持国际化)。
用户的权限码存放在用户的session中,由于我习惯上把用户信息放在一个User对象中,再保存到session中,所以这里我的想法是User对象中有个属性表示用户权限码,比如可以这样获取:
下面就开始说权限是如何设定的了。
先说说linux的文件权限设定,比如设定一个文件的权限111010010(所有者读写执行,同组读,其他人读),用了三组三位的二进制数,第一组是文件所有者,第二组是和所有者在同一组的用户,第三组是和所有者没有任何关系的其他人。每一组中,第一位表示“读”的权限,第二位表示“写”的权限,第三位表示“执行”的权限。好,我们的权限表示方法也出现了,allmapping元素的作用也显示出来了。allmapping中有n的mapping设定,mapping中name出现的顺序是有意义的,不过开发者不用关心它的顺序,让大家注意顺序是为了下面说明的更方便点。例如:
用户的权限最终表示成一个二进制数,当用户访问一个URL是,如果第i个mapping匹配了这个URL,就检查用户权限二进制数的第i位,如果该位为1说明用户有此权限,为0则说明用户无此权限。
OK,那么怎么设定用户权限呢?总不能随便给一串二进制数吧!当然不能。下面是两个设定用户权限的方法:
一:用户权限用二进制数表示,在负责权限管理的类中(所有的一切和validation一样,应该是有一个类库的)有getCode(mapping-name)方法,getCode返回一个n位二进制串,如果名字为mapping-name的mapping在第i位,则此二进制数的第i位为1,其他位为0。如果用户设定的权限有read和add,使用getCode(“read”)和getCode(“add”)获得两串权限码,再进行按位或运算就得到用户的最终权限码,用上面的设置,getCode(“read”)返回”100”,getCode(“add”)返回”010”,用户的权限码就是100|010=110,也就是读和添加权限。
二:用户权限用十进制数表示,经常用linux的朋友可能更喜欢这种方式,因为大家都喜欢用”chmod 744 文件名”的方式设定文件权限。这种方式中,负责权限管理的类返回的是一个10进制数,这个十进数的值和上面说的二进制数的值是相等的,比如二进制返回100,十进制就是4(二进制转十进制嘛!)。和上面相似,这次不是按位或运算,而是直接加运算。
还是设置读和添加权限,getCode(“read”)返回4,getCode(“add”)返回2,用户权限的表示就是2+4=6.
上面是总体方案,在具体实现时,用一个长整型数表示权限。还设计了一个接口:
其他细节还有url可以使用正则表达式,如果用户请求的url匹配多个配置项,那么只有用户的权限匹配所有的要求时才能算通过。这也安全性好一点。对没有配置的url,默认全部不需要任何权限,即任何人可访问。
在前台,我们一般都不会显示不想用户看到的超链接。比如对一个只有发布新闻的用户,肯定不想他看到删除新闻的链接。我的方案是在设计一个标签<privilege>有url属性,表示下面的操作要访问的url。如删除新闻:
标签的大致实现是:获取当前用户权限码,获取配置文件中url的权限码。如果当前用户的权限不足以访问该url,则skipbody,否则eavlbody。(个人觉得很方便,省去了一堆if)。
整体的思路就是这样,我写了一个实现,已经证明可行,自认为自己的OOD太差,代码写的也不精致。不敢再拿出来献丑,而且仅就实现这个方法来说,还是很容易的。
恳请各位提出不足或更好的方案,或为此方案写出漂亮的代码。
绞尽脑汁想出来一点,拿出来给高手看看,抛砖引玉,希望高手们能提出更好的方案,让大家以后权限管理的时候更轻松些。思考过程就不说了,没什么理论性的东西,无非是想想平时接触的操作系统,软家等的权限管理方式,再“灵光一闪”就得到了结果。
通过URL匹配控制访问权限,也就是在用户请求某个URL的时候,查看该用户是否有这个权限。这个“查看”是在一个Filter中进行的。判断用户是否有权限的标准是在一个xml文件中配置的。Dtd文档如下
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT privilege (globe-error?,allmapping,user-name,mapping*)>
<!ELEMENT globe-error (#PCDATA)>
<!ELEMENT allmapping (#PCDATA)>
<!ELEMENT user-name (#PCDATA)>
<!ELEMENT mapping (error?, message)>
<!ELEMENT error (#PCDATA)>
<!ELEMENT message (#PCDATA)>
<!ATTLIST globe-error redirect (false|true) "false">
<!ATTLIST error redirect (false|true) "false">
<!ATTLIST mapping
name CDATA #REQUIRED
url CDATA #REQUIRED
code CDATA #REQUIRED>
<!ATTLIST message key CDATA #IMPLIED >
Xml文档的核心是mapping元素,有url,code属性(必选)和error,message子元素。url表示匹配的URL,code是权限码,当用户的权限码符合这里的配置的权限码时,就认为用户用权限访问该URL,name属性唯一表示一个mapping。allmapping元素是的内容所有mapping元素name的集合,每个name之间用一个符号隔开,比如’|’或’,’都可以,用来帮助自动生成权限码,后面详细说明。Error(可选,如果没有则使用globe-error)是用户无权限时显示的错误页面,redirect属性(可选)制定forward到错误页面还是redirect到forward页面。message指定返回的错误信息(支持国际化)。
用户的权限码存放在用户的session中,由于我习惯上把用户信息放在一个User对象中,再保存到session中,所以这里我的想法是User对象中有个属性表示用户权限码,比如可以这样获取:
pcode=(User)session.getAttribute("user").getCode();//pcode就是用户权限码
下面就开始说权限是如何设定的了。
先说说linux的文件权限设定,比如设定一个文件的权限111010010(所有者读写执行,同组读,其他人读),用了三组三位的二进制数,第一组是文件所有者,第二组是和所有者在同一组的用户,第三组是和所有者没有任何关系的其他人。每一组中,第一位表示“读”的权限,第二位表示“写”的权限,第三位表示“执行”的权限。好,我们的权限表示方法也出现了,allmapping元素的作用也显示出来了。allmapping中有n的mapping设定,mapping中name出现的顺序是有意义的,不过开发者不用关心它的顺序,让大家注意顺序是为了下面说明的更方便点。例如:
<allmapping>read|add|delete<allmapping> <mapping name=”read” url=”/read.do”> <error>/errorpage.jsp</error> <message key=”error.read”>没有权限读取的信息</message> </mapping> <mapping name=”add” url=”/add.do”> <error>/errorpage.jsp</error> <message key=”error.add”>没有权限添加的信息</message> </mapping> <mapping name=”delete” url=”/delete.do”> <error>/errorpage.jsp</error> <message key=”error.delete”>没有权限删除的信息</message> </mapping>
用户的权限最终表示成一个二进制数,当用户访问一个URL是,如果第i个mapping匹配了这个URL,就检查用户权限二进制数的第i位,如果该位为1说明用户有此权限,为0则说明用户无此权限。
OK,那么怎么设定用户权限呢?总不能随便给一串二进制数吧!当然不能。下面是两个设定用户权限的方法:
一:用户权限用二进制数表示,在负责权限管理的类中(所有的一切和validation一样,应该是有一个类库的)有getCode(mapping-name)方法,getCode返回一个n位二进制串,如果名字为mapping-name的mapping在第i位,则此二进制数的第i位为1,其他位为0。如果用户设定的权限有read和add,使用getCode(“read”)和getCode(“add”)获得两串权限码,再进行按位或运算就得到用户的最终权限码,用上面的设置,getCode(“read”)返回”100”,getCode(“add”)返回”010”,用户的权限码就是100|010=110,也就是读和添加权限。
二:用户权限用十进制数表示,经常用linux的朋友可能更喜欢这种方式,因为大家都喜欢用”chmod 744 文件名”的方式设定文件权限。这种方式中,负责权限管理的类返回的是一个10进制数,这个十进数的值和上面说的二进制数的值是相等的,比如二进制返回100,十进制就是4(二进制转十进制嘛!)。和上面相似,这次不是按位或运算,而是直接加运算。
还是设置读和添加权限,getCode(“read”)返回4,getCode(“add”)返回2,用户权限的表示就是2+4=6.
上面是总体方案,在具体实现时,用一个长整型数表示权限。还设计了一个接口:
Privilege{
public long getPrivilege()
}//User对象应该实现这个接口,这样在Filter中我们使用
Privilege p=(Privilege)session.getAttribute("user");
p.getPrivilege();就可以获取权限码。
其他细节还有url可以使用正则表达式,如果用户请求的url匹配多个配置项,那么只有用户的权限匹配所有的要求时才能算通过。这也安全性好一点。对没有配置的url,默认全部不需要任何权限,即任何人可访问。
在前台,我们一般都不会显示不想用户看到的超链接。比如对一个只有发布新闻的用户,肯定不想他看到删除新闻的链接。我的方案是在设计一个标签<privilege>有url属性,表示下面的操作要访问的url。如删除新闻:
<privilege url="/deletenews.do">other</privilege>
标签的大致实现是:获取当前用户权限码,获取配置文件中url的权限码。如果当前用户的权限不足以访问该url,则skipbody,否则eavlbody。(个人觉得很方便,省去了一堆if)。
整体的思路就是这样,我写了一个实现,已经证明可行,自认为自己的OOD太差,代码写的也不精致。不敢再拿出来献丑,而且仅就实现这个方法来说,还是很容易的。
恳请各位提出不足或更好的方案,或为此方案写出漂亮的代码。
评论
hamlet
2007-07-27
其实权限管理目前最常用的就是基于角色的权限控制模型,尤其是在企业应用上,牵涉到的概念主要有角色、用户、菜单、功能、权限等,复杂的还可能会用用户菜单、代理等等,都是在角色权限控制模型的基础上扩展的,这方面的文章很多
姜太公
2007-07-25
to jomper
你可能没理解我的意思,我没说在界面隐藏action,是说在界面隐藏不希望用户看到的操作。比如在网站后台管理的页面中,超级管理员能看到“系统设置”这个链接,而信息发布员就看不到这个链接。既然看不到,当然不能点击,不点击,哪来的挫败感呢?^_^。我在前台使用<privilege>标签的目的正是为了不显示用户没有权限操作的链接。
你的每个操作使用的action作为匹配条件。比如add,对应的acion是AddAction,如果碰到一个Action类里不止是进行一种操作,假设它的名字叫MAction,它可能同时进行添加和删除,比如struts1的DisPatchAction,通过选择入口来完成不同的功能,那么add和delete是不是都要对应MAciton,还是使用别名机制?我觉得最简单的还是url方式。使用正则表达式+url重写时,这种方式功能是很强大的。
我不得不承认,使用角色的概念来分配权限更实用,我开始就说了,我是看了discuz对用户权限及其详细设定的功能后萌发出的自己实现一个权限管理的想法。在实际使用时,我们更多的还是使用角色的概念,是某个用户加入其中一个角色。或者扩展一下,一个用户可以同时属于多个角色,这样就更灵活了。我觉得你这个方法很好,有这样几个建议,一:对操作的匹配不能是Action的类名,应该是url或其他东西,二:如果权限不够,不能简单的发送错误页面,我认为应该有一个元素表示出现权限不够时的提示信息。
另:我修改了开始了设计,现在权限分配已经很方便了,你再看一下,变动的主要是文章的中间部分。头尾可以不看
你可能没理解我的意思,我没说在界面隐藏action,是说在界面隐藏不希望用户看到的操作。比如在网站后台管理的页面中,超级管理员能看到“系统设置”这个链接,而信息发布员就看不到这个链接。既然看不到,当然不能点击,不点击,哪来的挫败感呢?^_^。我在前台使用<privilege>标签的目的正是为了不显示用户没有权限操作的链接。
你的每个操作使用的action作为匹配条件。比如add,对应的acion是AddAction,如果碰到一个Action类里不止是进行一种操作,假设它的名字叫MAction,它可能同时进行添加和删除,比如struts1的DisPatchAction,通过选择入口来完成不同的功能,那么add和delete是不是都要对应MAciton,还是使用别名机制?我觉得最简单的还是url方式。使用正则表达式+url重写时,这种方式功能是很强大的。
我不得不承认,使用角色的概念来分配权限更实用,我开始就说了,我是看了discuz对用户权限及其详细设定的功能后萌发出的自己实现一个权限管理的想法。在实际使用时,我们更多的还是使用角色的概念,是某个用户加入其中一个角色。或者扩展一下,一个用户可以同时属于多个角色,这样就更灵活了。我觉得你这个方法很好,有这样几个建议,一:对操作的匹配不能是Action的类名,应该是url或其他东西,二:如果权限不够,不能简单的发送错误页面,我认为应该有一个元素表示出现权限不够时的提示信息。
另:我修改了开始了设计,现在权限分配已经很方便了,你再看一下,变动的主要是文章的中间部分。头尾可以不看
ltian
2007-07-25
楼上的,算你运气不好,论坛不稳定,我发的一大堆东西没有提示就给弄丢了,我没有兴致再写什么了.
只是说, 一方面从Role本身从组成结构上看是树,另一方面从类的继承关系上看是树,这是两种不同的树,弄混了当然设计得一蹋糊涂.
另外不赞成用XML来存储权限数据,根本不适合大型企业应用,推荐使用LDAP,如果不会开发LDAP,建议使用关系数据库来存储.
也不赞成把地域看成角色.地域最多和角色是引用关系.即一个地域里面可以有多个角色,一个角色可能属于一个地域.
从用户角度看,或者从你们的系统维护人员角度看,权限的东西应该集中存储,这样有利于权限的维护和更改,分布在各个模块里面,当后续授权发生变化时你要在N多模块里找那些文件?另外,模块划分还存在粒度问题?你把哪些算作一个可以放置权限文件的模块还是有争议的.所以集中存储URL不能与不对URL进行分类.
另外权限系统只做到对URL或者动作进行控制,仍然是初级的权限控制.再高一级的权限还应该控制数据.在很多企业级应用里面都要要求控制数据.比如说仓库管理员,都可以使用某个代表仓库管理的URL来进行仓库管理,但是你的权限必须控制在使用相同URL下不同的仓库管理员操作不同的仓库.
只是说, 一方面从Role本身从组成结构上看是树,另一方面从类的继承关系上看是树,这是两种不同的树,弄混了当然设计得一蹋糊涂.
另外不赞成用XML来存储权限数据,根本不适合大型企业应用,推荐使用LDAP,如果不会开发LDAP,建议使用关系数据库来存储.
也不赞成把地域看成角色.地域最多和角色是引用关系.即一个地域里面可以有多个角色,一个角色可能属于一个地域.
从用户角度看,或者从你们的系统维护人员角度看,权限的东西应该集中存储,这样有利于权限的维护和更改,分布在各个模块里面,当后续授权发生变化时你要在N多模块里找那些文件?另外,模块划分还存在粒度问题?你把哪些算作一个可以放置权限文件的模块还是有争议的.所以集中存储URL不能与不对URL进行分类.
另外权限系统只做到对URL或者动作进行控制,仍然是初级的权限控制.再高一级的权限还应该控制数据.在很多企业级应用里面都要要求控制数据.比如说仓库管理员,都可以使用某个代表仓库管理的URL来进行仓库管理,但是你的权限必须控制在使用相同URL下不同的仓库管理员操作不同的仓库.
ltian
2007-07-25
jomper 写道
to 姜太公:
1.如果你在界面隐藏了action,那么权限控制似乎就很模糊了,似乎你在界面就已经控制住了.而不需要其他地方再控制,最多只是防止直接用url访问资源。可能是我没理解你的意思.
2.角色的概念是很不错的,如果角色有个性那就应该是新的角色。通过角色来管理用户是很方便简洁的。
另外还有一个域的概念,角色我假设是个动作的集合,那么这个集合可以有不同的作用域。比如具体操作的某个范围。这样能减少角色的数量。
to ltian:
1.我实在想不明白你说的"向用户开放则url需要统一管理",单一的模块有他私有的动作,那么这些动作是没有必要暴露给其他模块的。完全可以在模块里配置。
2.关于角色树
这里有个很头疼的地方,到底是RoleTree,还是RoleImplTree。
一个具体角色是有很多children的,那么这里就有两个树。
比如
比如地区:
通过角色你如何形成一个
这样的树,通过RoleTree是无法实现的。
就拿工作流来说,一个任务派发个的是个人不是角色,RoleTree如何能实现呢?
1.如果你在界面隐藏了action,那么权限控制似乎就很模糊了,似乎你在界面就已经控制住了.而不需要其他地方再控制,最多只是防止直接用url访问资源。可能是我没理解你的意思.
2.角色的概念是很不错的,如果角色有个性那就应该是新的角色。通过角色来管理用户是很方便简洁的。
另外还有一个域的概念,角色我假设是个动作的集合,那么这个集合可以有不同的作用域。比如具体操作的某个范围。这样能减少角色的数量。
to ltian:
1.我实在想不明白你说的"向用户开放则url需要统一管理",单一的模块有他私有的动作,那么这些动作是没有必要暴露给其他模块的。完全可以在模块里配置。
2.关于角色树
这里有个很头疼的地方,到底是RoleTree,还是RoleImplTree。
一个具体角色是有很多children的,那么这里就有两个树。
比如
Admin implements UserRole, SubAdmin implements UserRole, CommonUser implements UserRole, 这个是RoleTree: Admin | SubAdmin | CommonUser
比如地区:
华中地区 implements DistrictRole, 湖北 属于 华中地区, 湖南 属于 华中地区, 省 implements DistrictRole, 武汉 属于 湖北, 市 implements DistrictRole, 武昌 属于 武汉,
通过角色你如何形成一个
华中地区 | | 湖北 湖南 | 武汉 | 武昌
这样的树,通过RoleTree是无法实现的。
就拿工作流来说,一个任务派发个的是个人不是角色,RoleTree如何能实现呢?
url,应该统一管理,在程序入口处统一加载并缓存之,这样程序效率高。我所有的URL和功能的对应都存储在数据库中的,我也没有使用XML来存储ROle或者URL,我根本就没有看好使用XML来作为权限数据存储这种方式。
凡使用XML作为权限存储载体的系统其实权限都是非常简单的。根本不适合企业级的权限。我理想中的权限系统是用LDAP来存储所有的权限相关数据的,这样利于大型系统的分布式权限的远程复制。
role从组成上看是树,从类的继承关系上看当然更是树,但不能把二者混淆。
从组成结构上看role是这样的:
public interface IRole
{
List getMemberRoles(); //List中的每个对象都是IRole类型即可。
}
这就实现了树状的Role,不会很难的。
从继承关系上看,树是这样形成的:
public abstract BaseRole implements IRole
{
}
public class abstract SysRole extends BaseRole
{
}
public class Admin extends SysRole
{
}
public class Guess extends SysRole
{
}
public class UserRole extends BaseRole
{
}
至于您所说的把地区看成是Role,我认为不大合适,地区那些可能是部门机构,或者是另外的数据资源。如果硬看成Role也可以.
public class DistrictRole extends BaseRole
{
}
一般来说, 区域应该是一种部门机构,如果你的角色在某个域中,那么域就是部门机构。一般来说,域是用来限制域内数据的提取的,其实和角色不是一回事,比方说属于湖北域内的客户,或者属于湖南域中的客户,这是你系统的数据资源,因此地域和role没有继承或者实现的关系最多是引用的关系,即Role从属于于那个区域。你可以让湖北的role去看湖南的客户信息,那是授权的问题。和程序本身没有关系。
工作流运行调度时派发任务最终当然是个人,但是你的工作流工具定义任务时可以接受角色或者部门,或者个人,或者是三者的组合来作为任务的处理者也可以用某个可以执行的程序作为任务处理者,那是工作流的事情,这和权限Role有明显的界限和接口。
关于权限的问题其实有很多内容,限于篇幅,就说这些吧!
jomper
2007-07-25
to 姜太公:
1.如果你在界面隐藏了action,那么权限控制似乎就很模糊了,似乎你在界面就已经控制住了.而不需要其他地方再控制,最多只是防止直接用url访问资源。可能是我没理解你的意思.
2.角色的概念是很不错的,如果角色有个性那就应该是新的角色。通过角色来管理用户是很方便简洁的。
另外还有一个域的概念,角色我假设是个动作的集合,那么这个集合可以有不同的作用域。比如具体操作的某个范围。这样能减少角色的数量。
to ltian:
1.我实在想不明白你说的"向用户开放则url需要统一管理",单一的模块有他私有的动作,那么这些动作是没有必要暴露给其他模块的。完全可以在模块里配置。
2.关于角色树
这里有个很头疼的地方,到底是RoleTree,还是RoleImplTree。
一个具体角色是有很多children的,那么这里就有两个树。
比如
比如地区:
通过角色你如何形成一个
这样的树,通过RoleTree是无法实现的。
就拿工作流来说,一个任务派发个的是个人不是角色,RoleTree如何能实现呢?
1.如果你在界面隐藏了action,那么权限控制似乎就很模糊了,似乎你在界面就已经控制住了.而不需要其他地方再控制,最多只是防止直接用url访问资源。可能是我没理解你的意思.
2.角色的概念是很不错的,如果角色有个性那就应该是新的角色。通过角色来管理用户是很方便简洁的。
另外还有一个域的概念,角色我假设是个动作的集合,那么这个集合可以有不同的作用域。比如具体操作的某个范围。这样能减少角色的数量。
to ltian:
1.我实在想不明白你说的"向用户开放则url需要统一管理",单一的模块有他私有的动作,那么这些动作是没有必要暴露给其他模块的。完全可以在模块里配置。
2.关于角色树
这里有个很头疼的地方,到底是RoleTree,还是RoleImplTree。
一个具体角色是有很多children的,那么这里就有两个树。
比如
Admin implements UserRole, SubAdmin implements UserRole, CommonUser implements UserRole, 这个是RoleTree: Admin | SubAdmin | CommonUser
比如地区:
华中地区 implements DistrictRole, 湖北 属于 华中地区, 湖南 属于 华中地区, 省 implements DistrictRole, 武汉 属于 湖北, 市 implements DistrictRole, 武昌 属于 武汉,
通过角色你如何形成一个
华中地区 | | 湖北 湖南 | 武汉 | 武昌
这样的树,通过RoleTree是无法实现的。
就拿工作流来说,一个任务派发个的是个人不是角色,RoleTree如何能实现呢?
姜太公
2007-07-25
to jomper
我是看了discuz的用户权限设定后想到自己做一个权限管理的一般方式,在discuz的后台用户权限管理中,可以对用户的权限做很详细的设定,包括对每个板块拥有发帖删帖附件等的权限的设定。
先说说你的设计吧,如果我没理解错的话,你的意思是权限是分配给"角色"的,判断用户权限的方法就是判断其所属的角色。在角色权限的配置中,设定了角色可以访问的action(是类似于URL的吧)。这样,当用户访问某个action时,判断其所属角色能否访问此action。
我也层考虑过带有角色的模型,在你说的action的地方用的是url。但有一个缺点是:某个用户不能有"个性"的权限,比如用户a属于角色admin,但这个角色的权限又太大了,而且又没有其他角色权限适合用户a,是不是要修改配置文件再添加一个角色呢?
使用url似乎是一个必然,如果只用action的类路径,碰到CRUD的时候恐怕就没法处理了。我在第一个帖子里也说在前台使用一个标签判断,这样如果用户没有权限就不会看到相应的url,除非别有意图的用户手工输入,这时可以引导到相应的页面,比如登录等,还可以显示一个友好的信息。
对参数的处理,我觉得方法还是url重写,或者干脆写在配置文件中,比如指定匹配aaa.do?a=a的url的权限应该是什么。
你的方法最好的地方,也是我的方法最不好的地方就是权限不能一目了然,全是01串,配置的时候容易出错。如果采用10进制数配置可以这样:
对n中权限,把对应的n位二进制数转为10进制。比如三种权限读写执行就是1,2,4。1表示读,2表示写,4表示执行。3就是读写,5是读执行,6是写执行,7是读写执行(似乎还是挺麻烦的)。
继续想……
我是看了discuz的用户权限设定后想到自己做一个权限管理的一般方式,在discuz的后台用户权限管理中,可以对用户的权限做很详细的设定,包括对每个板块拥有发帖删帖附件等的权限的设定。
先说说你的设计吧,如果我没理解错的话,你的意思是权限是分配给"角色"的,判断用户权限的方法就是判断其所属的角色。在角色权限的配置中,设定了角色可以访问的action(是类似于URL的吧)。这样,当用户访问某个action时,判断其所属角色能否访问此action。
我也层考虑过带有角色的模型,在你说的action的地方用的是url。但有一个缺点是:某个用户不能有"个性"的权限,比如用户a属于角色admin,但这个角色的权限又太大了,而且又没有其他角色权限适合用户a,是不是要修改配置文件再添加一个角色呢?
使用url似乎是一个必然,如果只用action的类路径,碰到CRUD的时候恐怕就没法处理了。我在第一个帖子里也说在前台使用一个标签判断,这样如果用户没有权限就不会看到相应的url,除非别有意图的用户手工输入,这时可以引导到相应的页面,比如登录等,还可以显示一个友好的信息。
对参数的处理,我觉得方法还是url重写,或者干脆写在配置文件中,比如指定匹配aaa.do?a=a的url的权限应该是什么。
你的方法最好的地方,也是我的方法最不好的地方就是权限不能一目了然,全是01串,配置的时候容易出错。如果采用10进制数配置可以这样:
对n中权限,把对应的n位二进制数转为10进制。比如三种权限读写执行就是1,2,4。1表示读,2表示写,4表示执行。3就是读写,5是读执行,6是写执行,7是读写执行(似乎还是挺麻烦的)。
继续想……
jomper
2007-07-25
ls的想法我也想过.
让 Role 成为权限控制的核心接口。
同时可以 在接口之间直接访问RoleTree.
部门机构树,是可以在角色第一次访问模块的时候生成xslt,xml则作为dom对象从缓存池里获取。
xml基本是不变的,变化的只是xslt.
另外:我不是做网站,是做电子运维,3楼的想法和公司的产品线无关,只是我个人的想法。
让 Role 成为权限控制的核心接口。
同时可以 在接口之间直接访问RoleTree.
部门机构树,是可以在角色第一次访问模块的时候生成xslt,xml则作为dom对象从缓存池里获取。
xml基本是不变的,变化的只是xslt.
另外:我不是做网站,是做电子运维,3楼的想法和公司的产品线无关,只是我个人的想法。
ltian
2007-07-25
jomper 写道
用我们公司目前的产品线就是url控制权限。
在经历开发以后发现url控制权限的几个问题:
1.url必须先暴露给客户.
但是往往客户希望所有暴露给他的功能都是能用的。不能用的url请求之后返回"没有权限"信息,会让客户有挫败感。这是不一定能被接受的。
2.url的注册往往需要集中到一个表里
让项目变的集成度很高.
3.似乎不能识别url传参数.
例如: aaa.do?a=a
我在3楼提出的方案,能把配置放在各自的模块里,这样便于管理发布。也很好读。各个模块之间耦合很少。
在经历开发以后发现url控制权限的几个问题:
1.url必须先暴露给客户.
但是往往客户希望所有暴露给他的功能都是能用的。不能用的url请求之后返回"没有权限"信息,会让客户有挫败感。这是不一定能被接受的。
2.url的注册往往需要集中到一个表里
让项目变的集成度很高.
3.似乎不能识别url传参数.
例如: aaa.do?a=a
我在3楼提出的方案,能把配置放在各自的模块里,这样便于管理发布。也很好读。各个模块之间耦合很少。
如果你的授权管理不向用户开放当然没有问题,如果向用户开放则url需要统一管理。当然可能你是做网站,而我说的是企业应用。
ltian
2007-07-25
以上的权限都很简单,权限如果仅提供这些功能,恐怕满足不了企业应用。尤其是以工作流为核心的企业应用的需要。
权限里面应该考虑 部门机构、人员、帐号、角色、功能、资源。
部门机构:是树状的,但是部门机构上级关系视图可以跟着应用进行变化。不同的应用可以看到不同的部门组织机构视图。不同的应用也可以根据需要,看到不同的部门组织机构同人员之间的不同视图。
其次,角色应该是树状层次的,而非单一列表状的。尤其是考虑到统一流程定义的时候。举例来说,库管是一个抽象角色,而不同仓库的库管则是该角色的子角色。在进行物资出库的时候,如果出库的物资是A库的,则工作单应该传递给,A库管这个角色。但你定义流程的时候,只能定义出库由库管这个抽象角色出库。至于具体A库管可以出A库物资,则由授权进行定义,或者根据业务规则进行定义,因此,规则引擎将会同权限里面的角色发生关系。这也是我比较关心的一个方向。
权限要控制数据资源,这里的资源并非URL,而是可以来自于数据库、LDAP、甚至XML里面的任何数据。权限要控制不同的角色在使用不同的功能时访问不同的数据。
权限里面应该考虑 部门机构、人员、帐号、角色、功能、资源。
部门机构:是树状的,但是部门机构上级关系视图可以跟着应用进行变化。不同的应用可以看到不同的部门组织机构视图。不同的应用也可以根据需要,看到不同的部门组织机构同人员之间的不同视图。
其次,角色应该是树状层次的,而非单一列表状的。尤其是考虑到统一流程定义的时候。举例来说,库管是一个抽象角色,而不同仓库的库管则是该角色的子角色。在进行物资出库的时候,如果出库的物资是A库的,则工作单应该传递给,A库管这个角色。但你定义流程的时候,只能定义出库由库管这个抽象角色出库。至于具体A库管可以出A库物资,则由授权进行定义,或者根据业务规则进行定义,因此,规则引擎将会同权限里面的角色发生关系。这也是我比较关心的一个方向。
权限要控制数据资源,这里的资源并非URL,而是可以来自于数据库、LDAP、甚至XML里面的任何数据。权限要控制不同的角色在使用不同的功能时访问不同的数据。
jomper
2007-07-25
用我们公司目前的产品线就是url控制权限。
在经历开发以后发现url控制权限的几个问题:
1.url必须先暴露给客户.
但是往往客户希望所有暴露给他的功能都是能用的。不能用的url请求之后返回"没有权限"信息,会让客户有挫败感。这是不一定能被接受的。
2.url的注册往往需要集中到一个表里
让项目变的集成度很高.
3.似乎不能识别url传参数.
例如: aaa.do?a=a
我在3楼提出的方案,能把配置放在各自的模块里,这样便于管理发布。也很好读。各个模块之间耦合很少。
在经历开发以后发现url控制权限的几个问题:
1.url必须先暴露给客户.
但是往往客户希望所有暴露给他的功能都是能用的。不能用的url请求之后返回"没有权限"信息,会让客户有挫败感。这是不一定能被接受的。
2.url的注册往往需要集中到一个表里
让项目变的集成度很高.
3.似乎不能识别url传参数.
例如: aaa.do?a=a
我在3楼提出的方案,能把配置放在各自的模块里,这样便于管理发布。也很好读。各个模块之间耦合很少。
姜太公
2007-07-25
minimu 写道
这样的权限设置太简单了,满足不了要求阿
我觉得的对一般的权限要求都是可以满足的,如果配合url重写几乎可以满足绝大多数的需求。
jomper
2007-07-25
我也设计了一个权限控制的模块,拿出来和lz探讨
角色动作关系配置:
permissions.xml
这个xml分散在每个模块里。
动作注册:
model-actions.xml
这个配置可以放在各个模块里,也能和所有的动作一起注册。注册后放容器里,至于是hashmap还是IoC容器看大家的需要了。反正不是Container就是AbstractFactory。
然后用一个ActionProxy 来处理,该角色是否拥有该动作的处理权。
这样能在各个模块里对配置的角色权限对应关系一目了然。
角色动作关系配置:
permissions.xml
<?xml version="1.0" encoding="UTF-8"?> <roles> <role name="admin"> <permission type="add"/> <permission type="create"/> <permission type="view"/> </role> <role name="member"> <permission type="add"/> <permission type="view"/> </role> <role name="anonymous"> <permission type="view"/> </role> </roles>
这个xml分散在每个模块里。
动作注册:
model-actions.xml
<?xml version="1.0" encoding="UTF-8"?> <actions> <action type="add" class="org.jomper.mana.action.AddAction"/> <action type="create" class="org.jomper.mana.action.CreateAction"/> <action type="view" class="org.jomper.mana.action.ViewAction"/> </actions>
这个配置可以放在各个模块里,也能和所有的动作一起注册。注册后放容器里,至于是hashmap还是IoC容器看大家的需要了。反正不是Container就是AbstractFactory。
然后用一个ActionProxy 来处理,该角色是否拥有该动作的处理权。
public class ActionProxy{
process("该用户的角色信息对象","该模块的权限对象","动作集对象");
}
这样能在各个模块里对配置的角色权限对应关系一目了然。
minimu
2007-07-25
这样的权限设置太简单了,满足不了要求阿
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 4262 次
- 性别:

- 来自: 合肥

- 详细资料
搜索本博客
我的相册
clack
共 1 张
共 1 张
最新评论
-
丢人阿,居然在指针上犯了 ...
最头大的是用c来搞unicode这样的数组
-- by t0uch -
丢人阿,居然在指针上犯了 ...
刚从其他语言换到c时最容易出错误的就是字符串处理了
-- by pi1ot -
C++子类对父类方法的覆盖
很简单的一些概念 不过你讲得好象很复杂...
-- by DraculaW -
C++子类对父类方法的覆盖
参见inside c++ object model另外可以对比一下基于模板的静态 ...
-- by taowen -
网站多用户权限管理的一个 ...
其实权限管理目前最常用的就是基于角色的权限控制模型,尤其是在企业应用上,牵涉到的 ...
-- by hamlet






评论排行榜