几乎在任何一个系统中,都离不开权限的设计,权限设计 = 功能权限 + 数据权限,而功能权限,在业界常常是基于RBAC
(Role-Based Access Control)的一套方案。而数据权限,则根据不同的业务场景,则权限却不尽相同,应该根据具体的场景巧妙设计。
作为曾经ERP的霸主,OracleE-Business Suite在国际上长期市场占用率在长期排名前二的市场,应用在各行各业,在二十年代末,二十一世纪出为甲骨文征战疆场、所向披靡的核心武器。
而Oracle财务是怎样去适配各行各业的数据安全性呢?
在了解EBS安全性的前提下,首先需要对EBS的架构做一个全局的理解(可以参考 http://www.360doc.com/content/10/0901/14/2050200_50374993.shtml)
主要有:
如果从上图来看概念有点模糊,其实从大体上简单理解(业务组 >= 法律实体 >= 业务实体 >= 库存组织 )
Oracle Virtual Private Database(简称VPD)是归属在Oracle安全security框架下的成熟产品。
简单的说,VPD就是介于用户SQL语句和实际执行对象之间的介质层。用户或者应用程序发出的SQL语句在传入到DBMS执行之前,会自动被拦截并且进行额外处理。处理的结果往往反映为在语句where条件中添加特殊的条件式
例如现在我们以先前的公司架构的维度进行举例:
假设数据表cux.cux_inv_all某公司可以查看所有物料信息,某些公司只能查看特定的物料,在没有VPD技术的情况下,我们必须修改程序代码将ORG_ID加入特定的数据表中
借助VPD,应用程序不需要修改代码,只需要指定数据库的一个策略就可以实现这一业务逻辑。
实现逻辑很简单,只需要注册一个policy即可以实现,具体代码如:
新建表
CREATE TABLE cux.cux_inv_all (
inv_num VARCHAR2(30),
inv_date DATE,
org_id NUMBER);
GRANT ALL ON cux.cux_inv_all TO apps;
CREATE OR REPLACE SYNONYM apps.cux_inv_all FOR cux.cux_inv_all;
CREATE OR REPLACE SYNONYM apps.cux_inv FOR cux.cux_inv_all;
insert into cux.cux_inv_all
(inv_num, inv_date, org_id)
values
('inv2021204', sysdate, 81);
insert into cux.cux_inv_all
(inv_num, inv_date, org_id)
values
('inv20212204', sysdate, 321);
添加策略,查看策略
begin
dbms_rls.add_policy(object_schema => 'APPS',
object_name => 'CUX_INV',
policy_name => 'ORG_SEG',
function_schema => 'APPS',
policy_function => 'MO_GLOBAL.ORG_SECURITY',
statement_types => 'SELECT, INSERT, UPDATE, DELETE',
update_check => true,
enable => true);
end;
select * from all_policies where object_name = 'CUX_INV';
当查看表cux_inv的时候发现没有值,当执行
exec mo_global.set_policy_context('S', 321);
select * from cux_inv;//可以查看到321的这条数据 单ORG_ID
begin
mo_global.init('CUX');
end;
select * from cux_inv;//可以看到所有的数据
接下来我们看EBS源码是怎么实现这个简单的功能的,追溯到核心代码无非是需要在mo_global.set_policy_context
进行初始化,然后再执行select的时候进行拦截,因为先前是注册policy_function
为MO_GLOBAL.ORG_SECURITY
也就联想到应该是在执行SELECT的时候通过此函数进行拦截
单业务实体:
先来查看MO_GLOBAL.ORG_SECURITY
看到最核心的代码是dbms_session.set_context(‘multi_org2’, ‘current_org_id’, p_org_id)和fnd_global.initialize(‘ORG_ID’,g_current_org_id) 就是将对应的公司注册到配置文件里面和对应的session中
ELSIF (p_access_mode = 'S') THEN
IF (g_access_mode is NULL OR g_access_mode <> 'S') THEN
--
-- If single operating unit access, then mode should be set to 'S'
--
dbms_session.set_context('multi_org', 'access_mode', p_access_mode);
g_access_mode := p_access_mode;
END IF;
IF (g_current_org_id IS NULL OR g_current_org_id <> p_org_id
OR sys_context('multi_org2','current_org_id') <> p_org_id -- Bug4916086
OR sys_context('multi_org2','current_org_id') is null) THEN
--
-- Set the current org context
--
dbms_session.set_context('multi_org2', 'current_org_id', p_org_id);
g_current_org_id := p_org_id;
-- Bug 7227733 Passing current org id to FND
fnd_global.initialize('ORG_ID',g_current_org_id);
END IF;
接下来我们查看MO_GLOBAL.ORG_SECURITY方法,核心代码如果是针对于单公司的就自动拼上org_id当前session_id对应的org_id
ELSIF g_access_mode IS NOT NULL THEN
IF g_access_mode = 'M' THEN
RETURN 'EXISTS (SELECT 1
FROM mo_glob_org_access_tmp oa
WHERE oa.organization_id = org_id)';
ELSIF g_access_mode in ('A','B') THEN
RETURN 'org_id <> -3113'; -- Bug5109430 filter seed data from policy predicate
ELSIF g_access_mode = 'S' THEN
RETURN 'org_id = sys_context(''multi_org2'',''current_org_id'')';
ELSIF g_access_mode = 'X' THEN
RETURN '1 = 2';
END IF;
针对于多OU的实现逻辑:
init -> set_org_context->populate_orgs 中将对应权限的公司插入到临时表mo_glob_org_access_tmp
IF(sync_ind = 'Y') AND ( t_delete_org_id.COUNT < t_pref_org_id.COUNT) THEN
FOR i IN t_common_org_id.FIRST .. t_common_org_id.LAST LOOP
INSERT
INTO mo_glob_org_access_tmp
(organization_id
, organization_name)
VALUES (t_common_org_id(i)
, t_common_ou_name(i));
-- needed for get_ou_tab function
g_ou_id_tab(i):=t_common_org_id(i);
END LOOP;
ELSE
FOR i IN t_org_id.FIRST .. t_org_id.LAST LOOP
INSERT
INTO mo_glob_org_access_tmp
(organization_id
, organization_name)
VALUES (t_org_id(i)
, t_ou_name(i));
-- needed for get_ou_tab function
g_ou_id_tab(i):=t_org_id(i);
END LOOP;
END IF;
g_ou_count := t_org_id.COUNT;
END IF;
在访问的时候其实只是增加exists
ELSIF g_access_mode = 'M' THEN
RETURN '(EXISTS (SELECT 1
FROM mo_glob_org_access_tmp oa
WHERE oa.organization_id = org_id))
OR (org_id = -3116)';
ELSIF g_access_mode in ('A','B') THEN
当然还可以根据安全性配置文件访问具体的安全性配置文件下面的公司,至此整个财务应收,应付模块的安全性主要是通过VDP进行打造.
总帐是最业务最简单的,但是安全性设置也是比较多的,大抵上分为分类账集,数据访问权限集,段安全性,交叉验证规则,访问权限集
类型 | 分类帐集 | 数据访问权限集 | 段值安全性 | 交叉验证规则 | 访问权限集 |
---|---|---|---|---|---|
应用场所 | 多个分类帐 | 分类帐、平衡段、管理段 | 段值 | 段值组合 | 报表等 |
作用域 | 能对多个分类帐同时控制 | 能限制分类帐、平衡度和管理段的选择和查看 | 能限制各个段的选择 | 能限制段值与段值之间组合的选择 | 能限制报表等功能的查看、使用和修改 |
应用逻辑 | 定义后,在职责配置文件”GL:数据访问权限集”下配置给各个职责 | 定义后,在职责配置文件”GL:数据访问权限集”下配置给各个职责 | 定义后,将安全性规则在分配界面根据不一样COA结构分配给各个职责 | 根据不一样COA结构定义后生效。 | 定义后,将安全性规则在分配界面分配给各个职责 |
界面体现 | 查看、新建和修改时选不到未定义的分类帐。 | 查看、新建和修改时选不到未定义的分类帐。新建或修改选到未定义段时会报没有权限的错误 | 看不到且选不到未定义的段。 | 选到定义不能组合在一块儿的段值组合时会报错。 | 使用权限,能够在生成复选框中选到;查看权限,能够定义界面看到定义但不能修改;修改权限(默认有查看权限),能够在定义界面中看到定义并改动, |
实现逻辑 | 就是按照将COA,期间未维度定义为一个分类账集合 | 对于界面的访问数据的权限,可以具体到一个账套,公司,以及对这个界面的读写操作权限(其实是分类账集更加细化版本) | 针对于具体的值集和职责对应关系 | 验证COA是否有效,对应的特定的科目和其他段值的相互验证。举例:假定 “会计弹性域”,其中“机构段”含有 00101 和 00102 两个值;‘部门段’包含10100-102999之间多个值,但是财富银行的政策规定“机构段”00101 使用 10101 至 10199 的部门段值,而“机构段”00102 使用 10200 至 10299 的部门段值。此时,可以创建交叉验证规则,确保用户无法创建值组合如 00101-10288 或 00102-101011 等的 会计科目帐户。 | 忽略 |
在数据安全性方面,ORACLE单单在总帐模块就用了5种安全性策略来满足用户的各种访问的限制的需求,具体归类而言: 分类帐集 和 数据访问权限集 是通过打包公司,账套作为一个集合来简化系统管理员分配权限;段安全性和交叉验证规则 是为了限制账户组合而存在;访问权限集 则限制报表。
在开发一个全新的系统中,是否能够借鉴Oracle EBS的这种数据安全策略呢?以便更好的进行拓展以及后续运维?
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/vipshop_fin_dev/article/details/120865326
内容来源于网络,如有侵权,请联系作者删除!