首页 > 解决方案 > VPD 策略失败并出现 ORA-28113:策略谓词有错误

问题描述

我有一个由“MANAGER”创建的名为 payroll 的表,其中包含以下内容:

EMP_ID               DEPT                      TOTAL      TAXES
-------------------- -------------------- ---------- ----------
E1                   accounting                 2400        100 
E2                   sales                      2500         75 
E3                   research                   3000        110 
E4                   operations                 4200        120 
E5                   sales                      4800        130 
E6                   sales                      2500         75 
E7                   accounting                 5200        140 
E8                   accounting                 2700        105 

我还有一个名为 employees 的表,也是由“MANAGER”创建的,其中包含:

ENAME                USER_ID              DEPT               
-------------------- -------------------- --------------------
SAMI                 E4                   operations           
ALI                  E7                   accounting           
MIRIAM               E5                   sales    

我在“经理”旁边还有两个用户“ALI”和“SAMI”,我想根据他们的部门限制他们对“工资单”表的访问,所以我给了他们在“员工”和“工资单”两个表上的选择权限我写了以下策略函数:

create or replace function sec_fun (p_schema varchar2, p_obj varchar2)
return varchar2
as
    v_dept MANAGER.employees.dept%type;
    v_user varchar2(100);
    v_id MANAGER.employees.user_id%type;
begin
    v_user:= SYS_CONTEXT('userenv', 'SESSION_USER');;
    select dept,user_id into v_dept, v_id from MANAGER.EMPLOYEES where ename=v_user;
    if (v_dept!= 'accounting') then
        return 'EMP_ID=' ||v_id;
    else
        return 'DEPT !=' || v_dept;
    end if;
exception
    when NO_DATA_FOUND then
        return null;
end;
/

然后我写道:

begin
    dbms_rls.add_policy(
      'MANAGER',
      'payroll',
      'p1',
      'MANAGER',
      'sec_fun',
      'select');
end;
/

现在当我连接为'ALI'然后写

SELECT * FROM MANAGER.PAYROLL;

在通过互联网阅读各种解决方案后,我多次查看并编辑了我的策略功能,出现以下错误:

Error at Command Line:1 Column:23
Error report:
SQL Error: ORA-28113: policy predicate has error
*Cause:    Policy function generates invalid predicate.
*Action:   Review the trace file for detailed error information.

非常感谢任何帮助。先感谢您

标签: oracleplsql

解决方案


有一些事情FGAC可以引发这种情况。

首先,如果谓词生成函数本身无效,则策略将始终抛出此异常。在此处提供的示例中,(第 8 行)的赋值v_user有双分号;;,这会导致编译失败。

当您为 运行 create 语句时sec_fun,您应该会收到如下消息:

Warning: Function created with compilation errors.
Elapsed: 00:00:00.483

由于谓词生成器存在语法错误,因此应用到的策略PAYROLL始终失败并显示ORA-28113.

需要注意的一点是,其中ORA-28113包含一个有用的建议:
Review the trace file for detailed error information.
当策略失败时,数据库会写入详细说明根本原因的跟踪文件。

无论如何,删除双分号后,这至少应该编译。但是,还有其他迫在眉睫的问题也会引发这种情况。

下一个问题是,所写的 return 语句也不是有效的谓词,因为它们没有创建 valid string literals

例如,“ EMP_ID = E1”是不可用的,因为它包含一个没有用引号括起来的文字。这同样适用于“ DEPT != accounting”谓词。

在下面的重做版本中,这些已被引用。

此外,FGAC通常更喜欢从所有执行分支中提供有效的谓词。
也许返回NULLwhenNO_DATA_FOUND可以在您的情况下工作,但最好返回一个有效的谓词(过滤所有数据)。您可能更愿意为不存在的员工抛出异常;在那种情况下NULL可能是可以接受的。这只是一个建议/想法。

需要注意的另一件事是,使用SYS_CONTEXT可能会有一些复杂性并且比要求的更冗长。除非有一些间接/嵌套/代理会导致当前用户不正确,否则可以直接使用该USER功能,并避免一些sys_context并发症。

这是一个替代版本,它应该编译,而不是抛出错误,并按照您描述的行进行过滤:

CREATE OR REPLACE FUNCTION SEC_FUN(P_SCHEMA VARCHAR2 , P_OBJ VARCHAR2) RETURN VARCHAR2 
AS
  V_DEPT EMPLOYEES.DEPT%TYPE;
  V_ID EMPLOYEES.USER_ID%TYPE;
BEGIN
  SELECT EMPLOYEES.DEPT, EMPLOYEES.USER_ID INTO V_DEPT, V_ID FROM MANAGER.EMPLOYEES WHERE EMPLOYEES.ENAME = USER;
  IF (V_DEPT != 'accounting')
  THEN
    RETURN 'EMP_ID = ' || CHR(39)||V_ID||CHR(39);
  ELSE
    RETURN 'DEPT != ' || CHR(39)||V_DEPT||CHR(39);
  END IF;
  EXCEPTION
  WHEN NO_DATA_FOUND
  THEN
    RETURN '1 = 0';
END;
/

推荐阅读