- MOAC简介
MOAC(Multi-Org Access Control)为多组织访问控制,是Oracle EBS R12的重要新功能。它可以实现在一个Responsibility下对多个OU(Operation Unit)进行操作,允许用户在不切换Responsibility的情况下,处理多个OU组织的事物。
UseràResponsibilityàSingle Operation Mode/Multiple Operation Unit Mode
2. MOAC
2.1、相关配置文件
1) MO:Security Profile(MO:安全性配置文件)
定义业务组
3) MO:Operation Unit(MO:业务实体)
2)如果设置了MO:Security Profile,且当前Responsibility仅能访问单个OU,将直接默认该OU,忽略MO:Default Operation Unit
3)如果设置了MO:Security Profile,且当前Responsibility可访问多个OU,首先将校验MO:Default Operation Unit设置的值是否在MO:Security Profile中,若存在,则默认MO:Default Operation Unit的值,否则为空。
4) 一个配置文件又分地点、应用产品、责任、用户层,默认级别为:用户>责任>应用>地点。
2.3、查看可用MOAC模块
MOAC需要应用程序做支持才能启用,所以在启用MOAC之前,需要清楚哪些应 用程序支持MOAC特性。
SELECT fmp.application_short_name FROM fnd_mo_product_init fmp WHERE fmp.status='Y' ;
也可对应用改程序注册 MOAC 支持,或取消 MOAC 支持
注册:fnd_mo_product_init_pkg.register_application
取消:fnd_mo_product_init_pkg.remove_application
3. VPD
MOAC是通过Oracle数据库的VPD(Virtual Private Database)技术来实现的,VPD技术提供了数据库对象(表、同义词、视图)
行级别访问的控制,使用VPD技术可以有效的限制用户获取数据的范围。
3.1 VPD工作方法
将一个或多个安全策略与表或视图关联后,就可以实现VPD。当对带有安全策略的表进行直接或间接访问时,数据库将调用一个实施该策略的函数,该策略函数返回一个访问条件(WHERE 字句),应用程序将它附加到用户的SQL语句,从而动态修改用户的数据访问权限。
例如:实现需求只允许某个用户查询管理员工表的数据,则VPD自动会将查询语句SELECT * FROM fnd_user添加查询条件
SELECT * FROM fnd_user where user_name = ‘HAND_CW’,其中‘where user_name=’HAND_CW’为VPD安全性策略函数返回的字符串。
3.2 VPD内容
1) policy_function
策略函数是作用在对象(表、视图、同义词)上,根据应用程序上下文返回一个特定的谓词,即自动在查询表、视图时,加上返回的where条件。可使用dbms_rls.add_policy将对象与策略函数绑定。
查看R12 MOAC使用的策略函数
SELECT DISTINCT dp.policy_name,
dp.package || '.' || dp.function,
dp.policy_type
FROM dba_policies dp
WHERE dp.policy_name = 'ORG_SEC';
2)policy_type
策略函数创建并返回的字符串具有很强的动态性,为了保证结果,提高性能,R12有一下几种策略类型:
context_sensitive,shared_context_sensitive,shared_static、static
设置策略函数的策略类型:
Dbms_rls.add_policy(policy_type => dbms_fls.shared_context_sensitive);
3.3 创建客户化表的VPD屏蔽
表:CUX_FREIGHT_INFO_HEADERS_ALL,同义词:CUX_FREIGHT_INFO_HEADERS
为同义词CUX_FREIGHT_INFO_HEADERS添加VPD屏蔽
BEGIN
dbms_rls.add_policy(object_schema => 'CUX', --数据表(或视图)所在的Schema名称
object_name => 'CUX_FREIGHT_INFO_HEADERS ', --数据表(或视图)的名称
policy_name => 'ORG_SEC ', --POLICY的名称,主要用于将来对Policy的管理
function_schema => 'CUX', --返回Where子句的函数所在Schema名称
policy_function => 'MO_GLOBAL.ORG_SECURITY', --返回Where子句的函数名称
policy_type => dbms_rls.shared_context_sensitive);
END;
创建该VPD屏蔽后,select * from CUX_FREIGHT_INFO_HEADERS没有返回结果集,
select * from CUX_FREIGHT_INFO_HEADERS_ALL可返回表的所有结果集
3.4 删除VPD
BEGIN
dbms_rls.drop_policy(object_name => 'CUX_FREIGHT_INFO_HEADERS',
policy_name => 'ORG_SEC');
END;
3.5 查看VPD
SELECT *
FROM user_policies t
WHERE 1 = 1
AND t.object_name = 'CUX_FREIGHT_INFO_HEADERS';
4. 支持MOAC的FORM开发
在R12版本中,OU的控制采购了MOAC的方式,是用户的操作得到了改善,如果客户化的form能够支持MOAC的功能,需要在界面上提供当前用户可选择的OU字段供用户选择。
4.1 定义FORM参数
mo_default_org_id、mo_default_ou_name、mo_ou_count
4.2 PRE_FORM
mo_global.init('CUX'); --根据应用去设置form为单OU或者多OU模式
mo_utils.get_default_ou(l_default_org_id, l_default_ou_name, l_ou_count); --得到默认的OU
copy(l_default_org_id,'PARAMETER.mo_default_org_id');
copy(l_default_ou_name,'PARAMETER.mo_default_ou_name');
copy(l_ou_count,'PARAMETER.mo_ou_count');
IF nvl(l_ou_count, 0) <= 0 THEN--判断是否找到了OU,如果没有找到,则报错
fnd_message.debug('错误001:没有找到相应的OU,请联系系统管理员或开发人员!');
RAISE form_trigger_failure;
END IF;
IF l_default_org_id IS NOT NULL THEN
mo_global.set_policy_context('S', l_default_org_id);
END IF;
4.3 WHEN_CREATE_RECORD
在带有OU的BLOCK的when-create_record中添加如下代码:
l_org_id_name := name_in('System.Trigger_Block') || '.ORG_ID';
l_block_item_name := name_in('System.Trigger_Block') || '.OU_NAME';
IF :parameter.mo_default_org_id IS NOT NULL
AND name_in(l_org_id_name) IS NULL THEN
copy(:parameter.mo_default_org_id,
name_in('System.Trigger_Block') || '.ORG_ID');
copy(:parameter.mo_default_ou_name,
name_in('System.Trigger_Block') || '.OU_NAME');
set_item_property(l_block_item_name,
item_is_valid,
property_true);
END IF;
备注:mo_utils.get_default_ou(l_default_org_id, l_default_ou_name, l_ou_count);
函数代码如下:
PROCEDURE get_default_ou(p_default_org_id OUT NOCOPY NUMBER,
p_default_ou_name OUT NOCOPY VARCHAR2,
p_ou_count OUT NOCOPY NUMBER) IS
l_prof_org_id hr_operating_units.organization_id%TYPE;
l_default_org_id hr_operating_units.organization_id%TYPE;
l_default_ou_name hr_operating_units.name%TYPE;
BEGIN
p_ou_count := mo_global.get_ou_count;
IF (get_multi_org_flag <> 'Y' OR p_ou_count = 0) THEN
RETURN;
END IF;
IF (p_ou_count = 1) THEN
BEGIN
SELECT mg.organization_id,
mg.organization_name
INTO l_default_org_id,
l_default_ou_name
FROM mo_glob_org_access_tmp mg;
EXCEPTION
WHEN OTHERS THEN
l_default_org_id := NULL;
l_default_ou_name := NULL;
END;
ELSE
l_prof_org_id := fnd_profile.value('DEFAULT_ORG_ID');
IF (mo_global.check_access(l_prof_org_id) = 'Y') THEN
l_default_org_id := l_prof_org_id;
l_default_ou_name := mo_global.get_ou_name(l_default_org_id);
ELSE
l_default_org_id := NULL;
l_default_ou_name := NULL;
END IF;
END IF;
p_default_org_id := l_default_org_id;
p_default_ou_name := l_default_ou_name;
EXCEPTION
WHEN OTHERS THEN
generic_error('MO_UTILS.Get_Default_OU',
SQLCODE,
SQLERRM);
END get_default_ou;