在RBAC权限控制模型中,有用户/角色/用户组/权限的概念.
现在遇到 一个问题,如果用户拥有多个角色,在使用系统时,在主页面可以切换角色.
在角色A时在主页面打开了一个弹出页面111.jsp,然后在在主页面切换到角色B. 这时再到111.jsp操作;
系统如何知道111.jsp应该使用角色A的权限.
注:因为页面比较多,没办法给每个页面都手动加一个请求参数来存储当前页面使用的角色,
是否有种高效的方法在页面打开时记录当前角色,并在页面再次活动时能够在请求中传递该页面的角色.

解决方案 »

  1.   

    RBAC权限控制模型不是很了解,推荐使用JAVA开源权限框架Spring Security2 (以前叫Acegi)来实现权限控制。
    无需“给每个页面都手动加一个请求参数来存储当前页面使用的角色,”。权限模型如下: 
    1.资源表:用来存储希望权限系统保护起来的东西。例如URL,方法(增、删、改、查等) ,也就是RBAC模型里说的“目标objects(OBS)”
    2.角色表:用户分类。 
    3.角色-资源对照表:角色所允许操作的资源。 
    4.用户表:具体的登录系统的用户帐户信息。 
    5.角色-用户对照表:用户所属的角色。一个用户可有多个角色。 
    6.功能菜单表:系统中允许操作的功能模块列表;列表中所列举的功能,除资源表中保护的外,均可直接使用。
    7.角色-菜单对照表:角色所允许操作的功能菜单列表;
    8.其它表:例如用户微调表、角色组等URL的控制基于HttpRequest拦截器(SS2里是filterSecurityInterceptor),用户每点击一个URL,先由权限系统判断该URL是否已被授权允许该用户访问,若未被授权,由抛出"未授权"异常,在操作界面捕获该异常并将提示信息显示出来。 方法的控制基于AOP实现,MethodSecurityIntercept。 参考:http://www.javaeye.com/topic/319965
      

  2.   

    你的 角色权限数据是应该存在于session 当中的 用户登陆时 应该把他所有的角色放入session   如果你要切换角色  最好是重新登陆新用户    或者重新造session
      

  3.   

    大权限下 可以用acegi或者是过滤器。
    但涉及到页面 及页面组建的权限 相对来说比较烦琐。我的思路是user选择权限后,将对应的权限放到内存中,如hashmap key值:user,vlue值:权限(举例,也可以用其他方式)。
    当user拥有A权限,打开a.jsp后(其中所有涉及到A权限的页面 都应该给予一定的标识,如加个隐藏域,告诉这个页面属于A权限所能操作的),
    又选择了B权限,当再来到a.jsp操作时,其value的权限已经是B了。而a.jsp中隐藏域的权限值为A,所以和当前权限不相符,固不能其进行操作。思路2(这个思路也是方法的一种,但未必灵活):
    同样要有对应权限的内存存储。但页面中要用到dwr。当user拥有A权限,打开a.jsp后 通过dwr的反转,建立一个连接。当user用户拥有B权限后,通过dwr将a.jsp关闭。无论用哪种方法,最主要的是要有一个中间量,这个中间量就是当前用户的权限。其它的都好说了。
      

  4.   

    确实是想实现不用给每个页面手动加一个请求参数来存储当前页面使用的角色,但你这里提到"当用户每点击一个URL,先由权限系统判断该URL是否已被授权允许该用户访问" 这就需要将所有url作为权限资源存储起来.而现在的情况是没有将页面的按钮、链接等微元素作为权限来分配,现在系统的权限只控制到一个菜单,这个菜单打开一个页面后,可以操作页面上的什么元素并没有控制,所以也就无法知道操作某个页面的一个元素时,作何种权限校验
      

  5.   

    你提的第一个思路考虑过,但这种方式要求给所有页面都加一个隐藏域来存储这个参数,这个参数还要能被带到弹出页面上,由于是对现有系统的修改,所以没办法把所有页面都加一遍。
    第二种方式没有需要在打架dwr框架,而目前使用了spring框架,需要改架构也是无法实行的。
      

  6.   


    非常感谢你详细的回复。
    正如你所说的,这需要系统的功能操作不能太多。否则处理起来很麻烦。
    在我处理的系统中,有些菜单是多个角色共用的,但是A角色打开这个菜单页面看到的,和B角色打开这个业务菜单看到的要求是不一样的。不知道有没有一种技术能够在一个页面打开时,服务器将参数写到这个页面,当这个页面再跟服务器通信时,又能将这个参数传递到服务器。这个参数肯定不会是放在隐藏域或者追加到url后面,因为这两种都需要修改具体的页面,增加隐藏域或者拼接到url后面。请大家再提供点建议
    再次感谢楼上几位的回复。
      

  7.   


    1.将所有需要保护的URL做为权限资源保存起来。这个是必须的。
    2.对方法类资源的保护的实现方式如下:
      下面以用户信息的CRUD(增删改查)为例描述
      (1).仍然是基于SS2,以AOP方式实现,核心是其MethodSecurityIntercept
      (2).程序框架为MVC架构,例如 struts2的Action + 业务逻辑层的service(可能还有接口层) + hibernate的DAO
          这三层通过spring来组装调用。业务层的service类是关键,AOP主要针对该层。
      (3).配置SS2的AOP,拦截业务层的service类的具体执行方法;
      (4).在权限模块的资源信息表中增加对CRUD方法信息,以对其保护
          yourpacketname.youServiceClass.ClassName
          要使功能强大些,可使用通配符,例如:yourpacketname.youServiceClass.do*
          这需要在资源信息判断时做些处理。
      (5).JSP界面,例如用户列表页有“删除”按钮,通过调用struts的action,相应的执行 yourpacketname.youServiceClass.UserInfoManager.delete(U)方法 
          打开用户列表页,允许操作人员点击“删除”按钮,客户端发出请求后,由SS2相应的判断该操作人是否具有执行delete(U)方法的权限。
          若没有权限,会抛出AccessDenied之类的异常。由action层tyr..catch..后在JSP页以弹出信息的方式提示:未获授权进行此项操作。
      (6).总结:
          对方法的权限控制,是等到该方法被执行时进行判断。
          若想不使用硬编码实现操作界面JSP可根据权限设置某些功能按钮禁用或可用状态,目前还没想到什么好的办法。欢迎各位大侠拍砖。
      (7).其它说明:
          不能对struts.Action方法进行拦截,会报错。
          不能对纯JSP的<%!  public XXX(){...}  %>这类方法拦截。    
      (8).具体示例代码如下:
      
      
      
       用户信息管理Service:
          
          //用户信息管理
          public class UserInfoManager<UserInfo> //可能该类是实现某个通用管理类的接口: implements ICommonManager<T> 
          {
           //新增
           public void addnew(UserInfo u){
           ...
           dao.save(u);
           }
          
           //修改
           public void update(UserInfo u){
           ...
           dao.update(u);
           }
          
           //查询
           public UserInfo getUserInfo(Long userId){
           ...
           return dao.loadById(userId);
           } 
          
           //删除
           public void delete(UserInfo u){
           ...
           dao.delete(u);
           }  
            
            //其它...
          } 
          
          
       SS2的AOP配置
          
    <aop:config>
    <aop:advisor id="methodForSecurity" advice-ref="methodSecurityInterceptor"
         pointcut="execution(* com.yourcompany.auth.service.UserInfoManager.(..))" />
    </aop:config>       
          
          这个pointcut可以根据实际代码配置,支持通配符,例如:execution(* com.yourcompany.service..*.*(..))
          
       JSP页的提示信息
          
          var opInfo = "<s:$opInfo>"
          if(opInfo!=null && opInfo.length>0) {
           alert(opInfo);
           return;
          }
          
         
       贴到blog啦,欢迎摘录。哈哈。  
       http://blog.csdn.net/denghan/archive/2009/06/11/4259528.aspx