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

12

我想使用Apache Shiro框架来保护我的Web应用程序(UI基于Vaadin 6)。我查看了Shiro网站上的所有示例,并进行了几个小时的搜索,但我无法找到处理以下要求的清晰方法。

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

Department A       - 用户在此处为“经理”
Department B
  Department C     - 用户在此处为“管理员”
    Department D

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

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

  1. 检查用户尝试查看的活动是否属于用户具有角色的部门;
  2. 检查用户是否具有所需的权限,以基于他在此部门中的角色为依据。

我目前遇到了一个理解问题,即如何实现不仅仅是“系统范围内角色”,而也是“此特定部门中的角色”的概念。

我该如何将上述示例转换为类似于“activity:view:123”这样的权限字符串?我在业务逻辑中将如何检查权限?

另一个疑问是关于Shiro的实现,我想使用一些开箱即用的解决方案,让我自己提供最少的实现工作。但是,看起来Shiro内置的实现仅适用于简单情况。是否有任何复杂授权实现的示例可供参考(可以覆盖上述情况)?

1个回答

3

我想描述一下我解决这个问题的方法,希望对某些人有用。我感觉这可能不是最优解,所以仍然欢迎任何更干净的实现建议。

假设我需要保护以下操作:

  • activity:edit
  • activity:view

我还需要确保权限不是系统范围的,而是依赖于我的部门角色。我在我的 Realm 中明确添加了“部门依赖”权限。例如(请参见本帖中的层次结构):

  • DEP_A:activity:view
  • DEP_C:activity:view
  • DEP_C:activity:edit

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

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

  • DEP_D:activity:view
  • DEP_C:activity:view
  • DEP_B:activity:view

如果我是部门 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() );
      }
   }

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接