Ralasafe Cookbook

概述

 

功能概述

Ralasafe访问控制中间件(数据级权限管理),是MIT协议开源免费软件产品。它使用图形化方式处理各种数据级权限管理问题,包括数据库行列级、字段内容级权限问题;它还能处理登录控制、功能级权限控制和URL权限认证。

使用获益

使用Ralasafe,可以做到:

  1. 权限与业务解耦合——实践更清晰的系统架构
  2. 权限管理完全图形化管理,不需要写一行代码或XML文件(基本配置信息除外,如数据源和用户元数据)——实践高效开发
  3. 所有访问控制被集中、规范化管理——实践访问模式的统一,减少安全漏洞

Ralasafe完全遵循JAVA EE规范,跨平台、web服务器和主流数据库。

架构与部署

 

架构

Ralasafe访问控制中间件包括2大部分:

  1. 权限引擎
  2. Web 管理控制端

权限引擎是jar包,1.1RC1版本大小846KB,非常精简。引用了castor、beanshell、jakarta-commons、gson等第三方包,共6.69M。权限引擎负责对权限策略进行解析,并返回解析结果。

Web 管理控制端,使用jQuery+jsp技术编写,展开大小1.79M。Web 控制端则负责图形化方式定制权限策略,在线图形化方式测试权限策略。

Ralasafe没有使用任何第三方框架,虽然给Ralasafe开发带来一些难度。但给集成Ralasafe开发者带来了更多福音:

  1. Ralasafe中间件无框架要求,可以和任何框架集成
  2. Ralasafe中间件无框架,和你将选用(或者已选用)的框架无冲突

部署

权限引擎是必须与应用集成部署的。

Web 管理控制端可选部署。你可以将Web 管理控制端与应用一起部署;你也可以只在开发 阶段使用,在生产部署时,不部署Web 管理控制端。

权限与业务解耦合

 

解耦合理论分析

权限与业务解耦合,非常有必要,也非常难。因为权限、尤其是数据级权限,与业务紧密耦合。有的时候甚至很难区分哪个是权限、哪个是业务;另外,需求变化也经常影响到权限模型、业务模型的变动。所有这些造成“数不清理还乱”的感觉。

只有实现如下目标,才能做到权限与业务解耦合,并适应不同需求和需求变化:

  1. 权限模型和业务模型,可以随时独立变动(增加、减少、修改等)
  2. 权限逻辑的变化,可以独立于业务进行修改也就是说,我们需要一个缓冲带、中间件!

Ralasafe做更多

Ralasafe就是这样的中间件,它能够适配业务模型、数据模型和权限模型,并将权限逻辑独立于业务进行集中管理。Ralasafe不仅实现了上述目标,而且做了更多:

  1. 集中管理权限
  2. 图形化管理权限
  3. 图形化测试权限
  4. 对权限逻辑变动,无需重启应用,即时生效
Ralasafe适配业务模型:查询权限可以将数据以你指定的业务模型(Javabean)格式返回;权限运算可以“钻取”业务数据的属性,进行权限规则计算;
Ralasafe适配数据模型:可以在线读取数据库表结构,在线定制数据查询,并指定查询返回结果以哪个业务模型(Javabean)格式返回;
Ralasafe适配权限模式:随时增加、修改权限模式,随时增加、修改权限策略。

权限API

Ralasafe API在你需要权限判断的地方,调用一下;就像LOG4J API那样,你在需要写日志的地方,调用一下。

功能级权限判断API一个;数据级权限判断API两个,分别对应从系统获取数据或者向系统提交数据两个方向——又称为查询权限、决策权限。

package org.ralasafe;
 
import org.ralasafe.entitle.Decision;
import org.ralasafe.entitle.QueryResult;
import org.ralasafe.user.User;
 
public class Ralasafe {
         public static boolean hasPrivilege(int privilegeId, User user) {
            ....
         }
 
         public static QueryResult query(int privilegeId, 
                User user, Map context)  {
             ....
         }
         public static Decision permit(int privilegeId, User user,
                Object businessData, Map context) {
             ....
         }
}

API非常简单,除了权限id(int privilegeId)外,不包含其他任何权限信息。也只有这样才能做到权限与业务解耦合。 所有权限逻辑全部在权限策略里面。当应用系统请求Ralasafe API的时候,Ralasafe权限引擎将解析相关权限策略,并返回解析结果。(如前面所说,权限策略由Ralasafe Web控制端图形化定制管理。)

权限ID

权限ID用来标识当前请求的是什么权限。查询员工权限呢,还是订单修改权限。权限ID可以通过Ralasafe Web 控制端导出,然后保存到你的业务常量类里面,如com.your.company.Constants

调用API时,直接使用常量引用,不需要使用数字了。如:

Ralasafe.hasPrivilege( Constants.QUERY_EMPLOYEE, user )

用户信息

权限判断还要告知当前用户是谁。该用户应该是成功通过身份验证的用户。你可以使用Ralasafe自带的LoginFilter来构建User,或者自行构建User对象。

自行构建User 对象非常简单:

import org.ralasafe.user.User;
 
User user=new User();
user.setId( userId );
user.set( "field1", value1 );
user.set( "field2", value2 );

new一个对象,然后使用set对User的各个属性进行设置。(Ralasafe对用户属性描述,通过用户元数据进行描述。描述用户表在哪里,用户表有哪些字段,分别代表什么业务意义。)

上下文

Map context指上下文,有的权限策略需要从上下文获取值进行权限计算,此时就需要提供上下文;有的权限策略不需要上下文,此时可以不必提供上下文,直接用null做参数。

我们考察这个策略:本人当前借款记录。该策略应该对应数据查询:

SELECT * FROM LoanMoney WHERE userId=? AND loanDate=?
  1. 其中第一个参数是用户id,Ralasafe引擎可以直接从User中“钻取”获得;
  2. 第二个参数是借款日期,表示当天。此时我们可以将当天日期放入上下文,Ralasafe自动从上下文“钻取”。如果我们约定该上下文键值(key)是today,那么调用Ralasafe的API是:
Map context=new HashMap();
context.put( "today", new java.util.Date() );
 
Ralasafe.query( privilegeId, user, context );

查询返回结果

Ralasafe查询权限返回QueryResult,包含这些信息:

  1. Collection<com.your.company.JavabeanAbc>,以你的业务模型格式返回的查询结果;如果没用查询权限,返回空集合(非NULL)
  2. int totalCount,为界面分页显示提供的,如果完整执行该查询可以返回总记录条数
  3. Collection<String> fields,当前用户允许查询业务模型哪些字段。比如订单有10个字段,当前用户能查看6个字段,这就表示那6个字段(注:如果当前用户只能查看6个字段,返回的Javabean也只设置这6个字段值,其他4个字段不予查询和设置值)
  4. Collection<String> readOnlyFields,当前用户对哪些字段是只读的,不能进行修改

决策返回结果

Ralasafe决策权限返回结果Decision,包含这些信息:

  1. boolean permit,是否允许当前用户对该数据(Object businsessData)进行操作
  2. String denyReason,如果拒绝当前用户对该数据(Object businessData)进行操作,拒绝理由是什么。

其他API

org.ralasafe.Ralasafe围绕这2大API还提供了其他API,如自定义条件查询 (输入CustomizedWhere条件),分页查询,只查询记录条数queryCount等

org.ralasafe.WebRalasafe是针对Web应用程序对Ralasafe进行封装。用户数据直接从 request.getSession()中获取,将拒绝理由设置到request.setAttribute()等,方便web程序的交互方式。可以参 考源码或者JavaDoc,此处不做详述。

权限模型概述

 

简介

Ralasafe权限控制包括2大部分:功能级权限控制和数据级权限控制。功能级权限控制使用通用的RBAC模型,即给用户赋予角色,给角色赋予权限。

Ralasafe通过对RBAC模型做简单扩展实现数据级权限,即给每个权限赋予一条或者多条权限策略。权限策略主要有:用户分类和资源两大要素组成。

当Ralasafe API被请求时,权限引擎会首先验证当前用户是否有功能权限;如果有功能权限,然后继续进行数据级权限验证。

核心概念

Ralasafe核心概念有:

  1. 用户分类
  2. 资源,主要是
    1. 业务数据分类
    2. 数据查询

这些概念并不是凭空捏造,都是来源于现实的权限需求,只是平常我们都会忽略了它们。让我们细细想想:

  1. 权限问题是否都是在探讨这样的问题:当什么情况下,怎么怎么样?当另一种情况下,又怎么怎么样?当另一种情况下,又怎么怎么样?……
  2. 这样的问题,总是可以用这种方式来解答:什么样的用户能看到哪些数据,操作哪些数据;什么样的用户又能看到哪些数据,操作哪些数据;…….
什么样的用户,就是“用户分类”!
能看到哪些数据,就是“数据查询”!!
操作哪些数据,就是“业务数据分类”!!!

用户分类

绝大部分人听到用户分类,都会想到角色。诚然,角色和用户分类都是对用户进行划分。但角色是一种静态划分;用户分类属于动态划分,是一种动态用户群组。

静态划分意思是:我们首先将某角色赋予给用户后,用户才隶属于该角色;

动态划分意思是:我们使用规则对用户进行描述,如果用户满足该规则描述,则属于该“用户分类”,无需事先将用户划到该用户群组。这种隶属关系是基于规则运算。

考察如下例子:

  1. 用户分类名称:总公司用户; 规则是:用户的机构ID=总公司机构ID
  2. 用户分类名称:分公司用户; 规则是:用户的机构 level=分公司机构level
  3. 用户分类名称:北京分公司用户;规则是:用户的机构ID=北京分公司机构ID

以上分类基于用户的属性进行规则判定。下面,再考察其他类型的分类:

用户分类名称:临时调查组用户;规则是:用户的id号在数据表临时调查组(SPEC_USER)有记录。

Ralasafe的用户分类是开放的,你可以通过Ralasafe Web控制端进行随意定制。还可以按照树形结构,将用户分类有规律的管理起来。

另外,通过Ralasafe创建角色的时候,Ralasafe会自动创建一个对应的用户分类——隶属该角色的用户分类。规则是:当前用户的角色集合中含有该角色,即如果当前创建的角色是管 理员角色,那么规则就是:当前用户的角色集合中含有管理员角色。

对于初学者,角色和用户分类概念不仅理解起来有点难度,使用起来也有一定难度。不知道什么情况下使用角色,什么情况下使用用户分类。

推荐准则:角色放在功能级控制层面;用户分类属于数据级控制层面。

总是思考这样的问题: “什么样的用户能看到哪些数据,操作哪些数据;什么样的用户又能看到哪些数据,操作哪些数据”。 就是考虑这个“样”,这个“范”,这个“style”。;-)

业务数据分类

业务数据分类和用户分类概念一致。用户分类是对用户的动态分类,基于规则描述,动态匹配计算;业务数据分类是对业务数据的动态分类,基于规则描述,动态匹配计算。

Ralasafe不限定该业务数据分类的类继承关系,也无需实现Ralasafe的某个接口类。只要是个JavaBean 就可以了。Ralasafe需要使用Java 反射技术对业务数据相关属性进行读取。比如 name属性,会反射调用getName()方法。

考察如下例子:

  1. 业务数据分类名称:大于5000的取款;规则是:金额字段值大于5000

继续考察如下复杂一些的例子:

  1. 业务数据分类名称:登录用户所在公司的订单;规则是:订单的机构id=登录用户的机构id
  2. 业务数据分类名称:加上本笔取款全体取款额大于20000;规则是:本笔取款额+数据查询(当天本人取款额之和)>20000

数据查询

数据查询和我们平常写的SQL查询概念一致,可以像Java PreparedStatement一样动态注入参数。

权限模型

有了上述概念后,我们详述一下Ralasafe的数据级权限管理模型。

查询权限模型

查询权限举例:人力专员按照机构层级查询员工。人力专员由RBAC角色控制,数据级权限策略如下:

策略序号用户分类数据查询
1 总公司用户 查询所有员工
2 分公司用户 查询所在分公司及下属营业部员工
3 营业部用户 查询所在营业部员工

决策权限模型

决策权限举例:每笔借款不超过5000元;每天借款总额又不能超过20000元。

策略序号决策用户分类业务数据分类拒绝理由
1 拒绝 所有人 大于5000的借款 单笔借款不能超过5000元
2 允许 所有人 加上本笔全天借款不超过20000的借款 全体借款总额不能超过20000元

权限数据来源

Ralasafe权限引擎会自动从固定值、用户、上下文、业务数据和数据库查询中“钻取”值,进行权限计算。权限规则可以是简单的比较计算(=,!=,& gt;,<,>=,⇐,),NULL判断计算(NULL, NOT NULL),IN集合比较(IN, NOT IN),也可以是上述规则组合形成规则组。规则组里面还可以嵌套规则组。

这些数据来源和计算规则,完全足够权限判断了。如果,你觉得不过瘾,Ralasafe还支持你书写原生态的Java代码,或者调用你的Java API。

在定制Ralasafe规则(用户分类、业务数据分类和数据查询)的时候,你可以使用这些权限数据。

固定值

就是确定值,不会变化的。比如定制用户分类——“总公司用户”时,规则是将用户的companyLevel属性与固定值1进行比较。

所以,我们定义了一个固定值变量headOfficeCompanyLevel,设置值等于1。

用户属性

如上面所说的“总公司用户”,需要读取用户属性companyLevel,我们定义了一个变量userCompanyLevel,设置值等于用户属性的 companyLevel。权限引擎计算时,会动态调用user.get( “companyLevel” ),然后将值付给userCompanyLevel。

定制数据查询——“登录用户所在公司”,其中where条件是company表的id字段等于用户的companyId属性。权限引擎计算时,会动态调用user.get( “companyLevel” ),设置到PreparedStatement查询参数里面。

业务数据属性

比如我们定制业务数据分类——“单笔借款大于5000元”。规则是用户数据的money属性与固定值5000做比较。权限引擎会自动调用传入对象的getMoney()方法获取值,与5000进行 比较。

LoanMoney money=new LoanMoney();
money.setLoanDate( new Date() );
 
User user=WebRalasafe.getCurrentUser(req);
money.setUserId( ((Integer)user.get( User.idFieldName ) ).intValue() );
 
String strMoney=req.getParameter( "money" );
money.setMoney( Integer.parseInt( strMoney ) );
 
if( WebRalasafe.permit( req, Privilege.LOAN, money, context ) ) {
         loanManager.addLoadMoney( money );
} 

如上代码,就会调用LoanMoney类的getMoney()方法。如果是其他类,也必须要有getMoney方法。

如果你指定业务数据属性是abc,那么该类必须要有getAbc()方法。总之,遵循通用的Javabean规范。

上下文值

比如我们定制数据查询——“本人当天借款记录”,其中有个where条件是LoanMoney表的loanDate属性等于“键值为today的上下文值”。

Map context=new HashMap();
context.put( "today", new java.util.Date() );
 
Ralasafe.query( privilegeId, user, context );

如上代码,我们将today放入上下文。权限引擎执行查询时,自动从上下文“钻取”参数,设置到PreparedStatement查询参数里面。

数据查询

Ralasafe的规则里面还能调用数据查询,将查询结果进行规则计算。比如,创建角色完毕后,自动生成的对应用户分类规则是:角色id是否在数据查询(当前用户所有角色集合)里面。 伪代码是:

roleId IN (Collection: query( SELECT roleId FROM ralasafe_ralasfe_role WHERE userId=${user.id} ) )

再比如业务数据分类——“加上本笔借款全体借款额不超过20000”。规则中也用到询——“查询本人当前总借款额”。该业务数据分类的规则是:

20000 - query( SELECT sum(money) WHERE userid=${user.id} AND loanDate=${context.today} ) >=${businessData}.money。

 

 

 

 

 

 

 

 

查询权限模型

查询权限举例:人力专员按照机构层级查询员工。人力专员由RBAC角色控制,数据级权限策略如下:

策略序号用户分类数据查询
1 总公司用户 查询所有员工
2 分公司用户 查询所在分公司及下属营业部员工
3 营业部用户 查询所在营业部员工
posted @ 2013-07-23 11:45  skyme  阅读(2442)  评论(1)    收藏  举报