浅谈OFBiz之权限设计(3)

看完了数据表设计,下面我们来看看代码实现,权限相关的代码被封装为"security"component,位于{Base_dir}/framework/security/src文件夹下,主要操作被抽象在名为Security的接口中,接口主要包含几个关键方法:

public Iterator<GenericValue> findUserLoginSecurityGroupByUserLoginId(String userLoginId);

public boolean securityGroupPermissionExists(String groupId, String permission);

public boolean hasPermission(String permission, HttpSession session);

public boolean hasEntityPermission(String entity, String action, HttpSession session);

public boolean hasRolePermission(String application, String action, String primaryKey, String role, HttpSession session);

public void clearUserData(GenericValue userLogin);

其中,

第一个方法是根据用户Id查询用户权限组;

第二个方法是check某个安全组是否拥有某个权限

第三个方法是判断某用户是否拥有某个权限(这里用户的相关信息被封装在session中)

第四个方法判断用户是否拥有某个实体的操作权限

第五个方法判断是否拥有某角色的权限

第六个方法清楚跟用户相关的所有缓存数据(该方法由framework在用户退出登录的时候调用)

注:上面三个hasXXX 方法都有不同的重载

再来看看OFBiz中的默认实现(OFBizSecurity.java)中的关键代码:

public boolean hasEntityPermission(String entity, String action, GenericValue userLogin) {
        if (userLogin == null) return false;

// if (Debug.infoOn()) Debug.logInfo("hasEntityPermission: entity=" + entity + ", action=" + action, module);
        Iterator<GenericValue> iterator = findUserLoginSecurityGroupByUserLoginId(userLogin.getString("userLoginId"));
        GenericValue userLoginSecurityGroup = null;

while (iterator.hasNext()) {
            userLoginSecurityGroup = iterator.next();

// if (Debug.infoOn()) Debug.logInfo("hasEntityPermission: userLoginSecurityGroup=" + userLoginSecurityGroup.toString(), module);

// always try _ADMIN first so that it will cache first, keeping the cache smaller
            if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + "_ADMIN"))
                return true;
            if (securityGroupPermissionExists(userLoginSecurityGroup.getString("groupId"), entity + action))
                return true;
        }

return false;
    }

这是对于hasEntityPermission的最终实现,我们可以看到,它会首先尝试在entity中追加“ADMIN”字符串,也就是说,先查看超级权限,如果拥有超级权限,则直接认为拥有权限,否则才会去查看细粒度的具体权限。

public boolean hasRolePermission(String application, String action, String primaryKey, List<String> roles, GenericValue userLogin) {
        String entityName = null;
        EntityCondition condition = null;

if (userLogin == null)
            return false;

// quick test for special cases where were just want to check the permission (find screens)
        if (primaryKey.equals("") && roles == null) {
            if (hasEntityPermission(application, action, userLogin)) return true;
            if (hasEntityPermission(application + "_ROLE", action, userLogin)) return true;
        }

Map<String, String> simpleRoleMap = OFBizSecurity.simpleRoleEntity.get(application);
        if (simpleRoleMap != null && roles != null) {
            entityName = simpleRoleMap.get("name");
            String pkey = simpleRoleMap.get("pkey");
            if (pkey != null) {
                List<EntityExpr> expressions = new ArrayList<EntityExpr>();
                for (String role: roles) {
                    expressions.add(EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, role));
                }
                EntityConditionList<EntityExpr> exprList = EntityCondition.makeCondition(expressions, EntityOperator.OR);
                EntityExpr keyExpr = EntityCondition.makeCondition(pkey, primaryKey);
                EntityExpr partyExpr = EntityCondition.makeCondition("partyId", userLogin.getString("partyId"));
                condition = EntityCondition.makeCondition(exprList, keyExpr, partyExpr);
            }

}

return hasRolePermission(application, action, entityName, condition, userLogin);
    }

上面的代码可以看到,在方法内部会先尝试调用hasEntityPermission,如果没有权限,则尝试在application后面追加"_ROLE"字符串来查看角色权限是否拥有,如果拥有则,直接返回,否则才会根据相关的Entity-NameRole表继续查找。 

Security_Group VS RBAC

我曾经在参与的一个项目中,接触过常用的RBAC(role based access control)权限设计思想。也曾转载过一篇OA的权限设计文章在OFBiz中弱化了角色的概念,而强化了“安全组”的概念。我认为是因为系统规模的不同造成的设计差异。RBAC常见于单一的系统设计,在单一的系统中,角色这个词定位准确而清晰;而在OFBiz中,它的目标是构建出一套ERP的平台(包含多个异构系统)。在跨越多个系统之上谈角色,反而变得模糊不清,导致混乱,但采用安全组的概念却不至于,安全组的概念使得权限的载体的粒度更细、更灵活,但同时也更为繁杂,因此其实OFBiz中还是有角色这个概念的(体现在权限中包含_ROLE的权限,可将其视为角色权限)。而常用的RBAC中通常也用到这种“安全组”的概念(一个特殊用户,需要分配有跨越多个角色的权限时,这时需要对该用户的权限进行定制化,这是就用得上类似的安全组的概念)。

因此我认为它们各适合不同的场景,但是可以互相结合的。

综述

这篇文章简要介绍了OFBiz中权限的设计,先阐述了OFBiz中权限的设计思想,然后概括了OFBiz中权限在哪些级别上起作用,紧接着分析了数据表设计,以及关键代码分析,最后对比了安全组的设计模式与RBAC的权限模型。

引用

https://cwiki.apache.org/confluence/display/OFBTECH/OFBiz+security

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ef9b5d70ed6f0124fc8e4b39192a6602.html