ralasafe查询级数据权限过程 代码剖析

 

按照ralasafe之前提供的demo 关于不同的HR来查询不同的人员的案例来剖析ralasafe是如何来做关于查询的数据级权限。 

 

首先在EmployeeServlet.java里会看到  

Collection employees= WebRalasafe.query(req,Privilege.QUERY_EMPLOYEE);

 

Ralasafe提供了2个接口RalasafeWebRalasafe,来与ralasafe打交道,包括query()//查询结果集,queryCount()//查询结果的条目,hasPrivilege()//判断是否有权限, permit()//做决策权限  getBusinessPrivilegeTree()//根据id,pid得到权限树 等等方法。顾名思义WebRalasafe是提供给web应用使用的接口,比如其中包括有一个用户的参数user,如果是WebRalasafe,我们直接从servlet api中取,给方法传一个HttpServletRequest就可以了,并不需要直接传用户参数,相信大家对这两个接口应该已经很熟悉了,WebRalasafe.query(req,Privilege.QUERY_EMPLOYEE);我们给query传了2个参数,一个是HttpServletRequest,一个是权限id.我们猜一下之后他会做什么:应该是从HttpSession取得当前用户,然后判断该用户是否有该权限(数据集权限首先会判断该用户对应的角色是否具有该权限,然后根据一系列的策略来判断不同的HR进来会看到不同的人员)OK,我们进到这个方法里面看看。 

 

 

 

他调用了重载的query方法,多了一个context参数,有的时候 我们的权限判断可能要从上下文当中取值,例子在cookbook里有,我就不多说了,这里我们不需要用到上下文参数,直接new HashMap()context 按照我们的猜想 第一步果然是从session中取得了当前操作的用户,接着又调用了Ralasafequery方法,看来WebRalasafe是在Ralasafe的基础上又封装的一层拱WEB层使用,他返回的是一个QueryResult。进入QueryResult里看看

 

我们看到了有5个属性,集合类型的datafieldsreadOnlyFieldsint类型的totalCount和布尔类型的reachQueryLimitData代表你要查询的数据结果集合,fields代表你可以操作业务模型的哪些字段,ralasafe可以控制到数据行列级的权限粒度。readOnlyFields代表对当前用户哪些字段是只读的。totalCount顾名思义肯定是返回的结果数目,reachQueryLimit这个应该是在决策权限时候判断是否有决策权限用的。其实按照DEMO的要求 我们只需要返回data即可,因此如上图他返回的也是queryResult.getData()集合。知道了返回值 我们继续往下面跟踪。 

 

 

EntitleManager是啥玩意?我们看看该接口封装的一系列方法: 

 

 

很明显了,RalasafeWebRalasafe封装的方法 底层的操作全部来自于EntitleManager控制,其中的很多方法 我们联想一下web界面的一些操作,比如增加查询,删除查询,测试查询等等操作 都会调用到这个接口,你一看名字就可以知道他的用途了,所以说一个好的命名规范是非常重要的,还有ralasafe的层次真的很清晰 很容易读懂,可以说EntitleManager是整个ralasafe的核心类。 接着往下看,取到EntitleManager的实现类后,继续调用query方法,这次是EntitleManagerImpl类的query方法,上图。

 

 

参数包括权限Id(这个是常量,需要用户自己从WEB界面导出添加到应用里,对应的是数据库中ralasafe_privilege表中的id),当前的用户,还有上下文(这里我们只是new HashMap,对我们这个DEMO没实际意义。),首先做了一个判断,按照最开始的猜想,他会先判断当前用户对应的角色是否具有该权限,调用hasPrivilege(user,pvlgId),可能有些人不明白为什么要要先对角色权限的判断 而不直接进入策略判断,按照老汪给我的指点是这样的:Ralasafe为了安全起见,调用数据级权限时,Ralasafe权限引擎会自动先判断功能级权限;以免开发者或者调用者没有调用功能级权限直接调用数据级权限。进入到hasPrivilege方法里,上图。

PrivilegeManager接口封装了操作权限表的一系列操作,还是上个图比较清晰.

我们可以看到很大一部分是和操作数据有关的CRUD,其中不乏getParent(得到父节点,ralasafe的权限是通过树的形式管理,因此必须有很清晰的父子编号)。就不多说了 一看结构都会明白的。回到hasPrivilege方法,pvgMng.getPrivilege(id) 他是怎么来取id对应的记录?ralasafe是把所有的业务权限和非角色权限分开分别放到了一个以idkeymap里,然后根据id去集合里看看有没有该id对应对应的权限,(我估计这里应该是有对集合做了缓存了吧?)。如果不存在就会抛出不存在该权限的异常。回到hasPrivilege方法,接着往下走 我们又看到了一个新的类ApplicationManager,因为我们的应用中配置了2个数据库,一个是ralasafe(ralasafe-db.properties)和我们自己业务数据库(对应app-ds.properties) 通过applicationManager.getApplication(appName)可以得到对应的是哪个应用,但是我翻看了数据库中的application中只有一条记录 就是ralasafeRalasafe实现了缓存,他会到缓存中去拿appName对应的application记录,因为这种记录数据改变的几率是很小的,一般定义完后就不会去碰他了,因此命中率基本上是百分百吧,因此用缓存还是比较合适的,返回的是一个Application类型,里面有3个属性name description 和集合类型的userTypes。分表表示当前的应用的名字 描述 和在最开始安装ralasafe对应的用户元信息.appNameuserTypeName传给getUserRoleManager()方法,得到userRoleManager的实现类,又是一个manager,我们先回忆一下之前说的几个manager类:EntitleManager(相当于dao 封装了操作数据库的方法) ApplicationManager(管理当前的应用和用户元数据信息)  PrivilegeManager(封装了一些列操作权限的方法现在的UserRoleManager(是用于管理用户角色的,方法和前面几个类基本相似)。还是回到hasPrivilege方法,我们回忆一下到这一步之前我们完成的工作:根据权限ID得到了权限类,得到了角色管理类(是通过先获取applicationManager,再通过该类获取Application,得到UserType,最后根据appNameUserType得到角色管理类),有些人说获取一个实现类要传参数,这里还是会涉及到缓存,大家知道最简单缓存就是基于map实现的,那么必然需要有一个KEY值,而这个KEY 就是入参。OK,继续往下走,调到了userRoleManager.hasPrivilege(userid,pvlgId),如下图,该方法会判断当前权限的类型是否是非角色权限 如果是就直接返回,因为没必要判断了,否则继续往下,根据用户,会到ralasafe_ralasafe_userrole表里查找该用户对应的角色有哪些,注意是一个集合,因为一个用户可以拥有多个角色,遍历该集合,对于每一个角色 都会调用RoleManager类里重载的hasPrivilege(roleId,pvlgId)方法:该方法是这样做的,根据角色idralasafe_roleprivilege表里查找该角色对应的所有权限,然后和pvlgId比较 如果有相等的 就吧hasPrivilege设为true,说明该角色有该权限。OK 判断权限到此为止。可能看文字比较乱 下次我将画一个流程图 这样会更清晰。还记得最开始我们调用的query方法吗,现在只是判断用户对应的角色是否具有权限,后面的数据级策略判断的代码分析 将在过几天后揭晓。

 

你可能感兴趣的:(代码)