如何使用Apache Shiro处理分层角色/权限?

时间:2013-07-01 13:36:03

标签: security vaadin shiro rbac

我正在尝试使用Apache Shiro框架来保护我的Web应用程序(UI基于Vaadin 6)。查看Shiro网站上的所有示例,并搜索了几个小时,但我找不到一个干净的方法来处理以下要求。

假设应用程序是一种项目管理工具,用户在其中创建属于公司层次结构中特定部门的活动。每个用户可以在多个部门工作,并且在每个部门中具有不同的安全角色。例如:

Department A       - User is 'Manager' here
Department B
  Department C     - User is 'Admin' here
    Department D

用户是A部门的'经理' 用户是C部门的“管理员” 用户还应该继承部门D(它是部门C的祖先)的“管理员”角色。

因此,基本权限检查(假设我想查看属于某个部门的活动)将是:

  1. 检查活动用户是否正在尝试查看属于部门用户的角色;
  2. 根据本部门中的角色检查用户是否需要获得许可。
  3. 我目前仍然不了解如何实施“系统范围的角色”,而是“在这个特定部门中扮演角色”的概念。

    如何将上面的示例转换为权限字符串,例如“activity:view:123”?我将如何检查业务逻辑中的权限?

    另一个疑问是与Shiro的实现,我想使用一些开箱即用的解决方案将提供我自己的实现的最小努力。但是,似乎Shiro的内置实现仅针对简单的情况而设计。是否有任何复杂授权实现的例子(可以涵盖上述情况)?

1 个答案:

答案 0 :(得分:3)

只想描述我对这个问题的解决方案,这可能对某些人有用。我觉得这可能不是最优的,所以仍然对任何有关清洁实施的建议持开放态度。

假设我需要确保以下行动:

  • 活动:编辑
  • 活性:图

我还需要确保权限不是系统范围的,而是取决于我在特定部门中的角色。我所做的是在我的Realm中为用户明确添加了“部门依赖”权限。示例(请参阅帖子中的层次结构):

  • DEP_A:活动:图
  • DEP_C:活动:图
  • DEP_C:活动:编辑

每次我想检查是否允许针对某些活动采取行动时,我都会创建一个要检查的权限列表。例如:

活动A属于D部门,我想“查看”它。检查的权限将是:

  • DEP_D:活动:图
  • DEP_C:活动:图
  • DEP_B:活动:图

如果我是C部门的管理员,我会获得'DEP_C:activity:view'权限,因此我会 检查将通过。这允许在公司结构层次结构中实现权限继承。

以下是我的服务类负责权限检查的代码片段:

   @Override
   public void checkIfOperationPermitted( SecurityOperation operation, 
      Object object )
   {
      final Subject currentUser = SecurityUtils.getSubject();

      if(currentUser.isPermitted(
         SecurityOperation.SYSTEM_ADMIN.getPermissionString()) ||
         currentUser.hasRole( "admin" ))
      {
         // no need to check anything else,
         // admin is system wide role.
         return;
      }

      if(object instanceof Activity)
      {
         // Activity permissions fully depends on organization and
         // product hierarchies. PermissionResolver is just a class
         // which generates list of permission strings based on 
         // department activity is belonging to.
         Activity a = (Activity) object;
         List<String> permissionsToCheck = 
            permissionResolver.resolveHierarchicalPermissions(operation, a);
         boolean permitted = false;
         for(String permission: permissionsToCheck)
         {
            if(currentUser.isPermitted( permission ))
            {
               permitted = true;
               break;
            }
         }
         if(!permitted)
         {
            throw new UnauthorizedException( "Access denied" );
         }
      }
      else
      {
         // Check for system wide permissions
         currentUser.checkPermission( operation.getPermissionString() );
      }
   }

我想到的另一种方法是在我的Realm中为用户添加所有这些权限,但拒绝了这一点,因为公司层次结构通常可以包含N层 - 这极大地增加了特定用户(内存使用)的权限列表中的重复。

相关问题