向用户 Oracle 授予更新

Posted

技术标签:

【中文标题】向用户 Oracle 授予更新【英文标题】:Grant update to user Oracle 【发布时间】:2017-12-06 18:44:53 【问题描述】:

我想将更新权限授予表客户的经理,但仅限于其作为经理的客户。

例如,我有一个表客户,我使用命令 CREATE USER 创建了一个用户“Jean”,所以我希望“Jean”可以修改它作为经理的所有客户。

【问题讨论】:

在表级别授予访问权限。您要求在行级别授予访问权限的东西,Oracle 不支持。也许您可以使用触发器来完成您正在尝试做的事情。祝你好运。 可能,Oracle 具有行级安全性 (RLS),VPD,以及 Oracle 级安全性 (OLS)。使用什么有重叠,对于 Oracle 来说是典型的,它有点复杂。 另一种解决方案是创建一个仅包含允许更新的行的视图,然后对其进行更新。这确实要求视图是可更新的,这可能会变得复杂。有关其工作原理的详细信息,请参阅this answer。 数据库的哪个版本和版本?实现这一点的最简洁方法是细粒度访问控制(即 DBMS_RLS 策略),但这需要企业许可证。 您是否有理由要在数据库表级别执行此操作?对我来说,这听起来像是在应用程序级别执行起来更容易、更清晰的规则。 【参考方案1】:

我找到了此 RLS 示例,但为满足您的简单 USER 要求进行编辑为时已晚。此示例迎合了具有可能从组织树继承的许多不同角色的用户。但我希望你明白吗?

BEGIN
  DBMS_RLS.DROP_POLICY (object_schema    => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_READ');

  DBMS_RLS.DROP_POLICY (object_schema    => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_WRITE');

  DBMS_RLS.DROP_POLICY (object_schema    => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_REGISTER');

END;

CREATE OR REPLACE PACKAGE chs_security_policies AS

    ROLE_CRUM            CONSTANT VARCHAR2(5) := 'CRUM';
    ROLE_CRUO            CONSTANT VARCHAR2(5) := 'CRUO';
    ROLE_HOU             CONSTANT VARCHAR2(5) := 'HOU';
    ROLE_DCO             CONSTANT VARCHAR2(5) := 'DCO';
    ROLE_SA              CONSTANT VARCHAR2(5) := 'SA';
    ROLE_CA              CONSTANT VARCHAR2(5) := 'CA';
    CHS_ORG_TREE         CONSTANT CHAR(5)     := 'CHS01';
    READ_ACCESS          CONSTANT INTEGER     :=   63;
    WRITE_ACCESS         CONSTANT INTEGER     :=   42;
    INSERT_ACCESS        CONSTANT INTEGER     :=   64;
    ORG_CASCADE          CONSTANT INTEGER     := 2060;
    CASE_SPECIFIC        CONSTANT INTEGER     :=   48;
    QUARANTINED_ACCESS   CONSTANT INTEGER     :=  128;
    FINALISED_ACCESS     CONSTANT INTEGER     :=  256;
    READ_ONLY            CONSTANT INTEGER     :=   21;
    READ_CASE_ORG_UNITS  CONSTANT INTEGER     :=   16;
    READ_GROUP_ORG_UNITS CONSTANT INTEGER     :=    4;
    READ_WORLD_ORG_UNITS CONSTANT INTEGER     :=    1;

    FUNCTION case_file_read     (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2;

    FUNCTION case_file_write    (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2;

    FUNCTION case_file_register (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2;

    FUNCTION case_file_filter   (i_schema IN VARCHAR2, i_object IN VARCHAR2, i_access_requested INTEGER)
      RETURN VARCHAR2;

    FUNCTION check_case_access  (i_case_file_id IN INTEGER, i_mgr_org_unit IN INTEGER, i_dco_person_id in varchar2)
      RETURN INTEGER
      DETERMINISTIC;

    FUNCTION default_priv_mask  (i_person_id in varchar2) 
      RETURN INTEGER
      DETERMINISTIC;

    FUNCTION decode_role        (i_case_file_id IN INTEGER, i_mgr_org_unit IN INTEGER, i_dco_person_id in varchar2)
      RETURN VARCHAR2
      DETERMINISTIC;

    FUNCTION check_proxy_access (i_case_file_id         IN case_file.case_file_id%type
                               , i_dco_person_id        IN case_file.dco_person_id%type
                               , i_mgr_org_unit         IN case_file.mgr_org_unit%type
                               , i_proxy_person_id      IN case_file.dco_person_id%type)
      RETURN INTEGER
      DETERMINISTIC;

END chs_security_policies;

CREATE OR REPLACE PACKAGE BODY chs_security_policies AS

    FUNCTION case_file_read (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2
    IS

    BEGIN

      RETURN case_file_filter(i_schema, i_object, READ_ACCESS);

    END case_file_read;

    FUNCTION case_file_write (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2
    IS

    BEGIN

      RETURN case_file_filter(i_schema, i_object, WRITE_ACCESS);

    END case_file_write;

    FUNCTION case_file_register (i_schema IN VARCHAR2, i_object IN VARCHAR2)
      RETURN VARCHAR2
    IS

    BEGIN

      RETURN case_file_filter(i_schema, i_object, INSERT_ACCESS);

    END case_file_register;

    FUNCTION case_file_filter (i_schema IN VARCHAR2, i_object IN VARCHAR2, i_access_requested INTEGER)
      RETURN VARCHAR2
    IS

      o_filter_predicate VARCHAR2(200) := '';      

    BEGIN

      CASE lower(i_object)
      WHEN 'case_file' THEN
        o_filter_predicate := 
          'BITAND(chs_security_policies.check_case_access(case_file_id, mgr_org_unit, dco_person_id), '||i_access_requested||') <> 0 ';
      WHEN 'case_file_h' THEN
        o_filter_predicate := 
          'BITAND(chs_security_policies.check_case_access(case_file_id, mgr_org_unit, dco_person_id), '||i_access_requested||') <> 0 ';
      END CASE;

      RETURN o_filter_predicate;

    END case_file_filter;

    FUNCTION check_proxy_access (i_case_file_id         IN case_file.case_file_id%type
                               , i_dco_person_id        IN case_file.dco_person_id%type
                               , i_mgr_org_unit         IN case_file.mgr_org_unit%type
                               , i_proxy_person_id      IN case_file.dco_person_id%type)
      RETURN INTEGER
      DETERMINISTIC
    IS
      o_has_access       INTEGER     := 0;
      v_prev_person      varchar2(8) := SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER');

    BEGIN

      dbms_session.set_identifier(i_proxy_person_id);

      IF BITAND(check_case_access(i_case_file_id, i_mgr_org_unit, i_dco_person_id), READ_ACCESS) <> 0
      THEN
        o_has_access := 1;
      END IF;

      dbms_session.set_identifier(v_prev_person);

      RETURN o_has_access;

    END check_proxy_access;

    FUNCTION check_case_access(i_case_file_id in INTEGER, i_mgr_org_unit in INTEGER, i_dco_person_id in varchar2) 
      RETURN INTEGER
      DETERMINISTIC
    IS

      o_access_granted   INTEGER     := 0;
      v_curr_person      varchar2(8) := SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER');
      v_single_priv      INTEGER     := 0;
      v_profile_org_unit INTEGER     := 0;
      v_quarantine_ok    varchar2(1);
      v_finalise_ok      varchar2(1);
      v_is_participant   varchar2(1);
      v_local_role       access_role.role_code%type;

      cursor user_privs is
        select 
               d.priv_id,
               b.org_unit_id,
               c.role_code
        from   
               access_user      a
              ,access_profile   b
              ,access_role      c
              ,access_role_priv d
              ,access_priv      e
        where  
               a.person_id      = v_curr_person 
          and  a.active_flag    = 'Y'
          and  b.person_id      = a.person_id
          and  c.role_code      = b.role_code
          and  d.role_code      = b.role_code
          and  e.priv_id        = d.priv_id
      ;

    BEGIN

      IF v_curr_person is null
      THEN
          RETURN 0;
      END IF;

      select 
        case
           when exists 
              (select
                      *
                 from
                      complainant a
                where
                      a.case_file_id      = i_case_file_id
                  and a.person_id         = v_curr_person
                  and a.active_flag       = 'Y'
              )
           then  'Y'
           else  'N'
        end
      into 
        v_is_participant
      from 
        dual
      ;

      IF v_is_participant = 'Y'
      THEN
          RETURN 0;
      END IF;

      select 
        case
           when exists 
              (select
                      *
                 from
                      respondent a
                where
                      a.case_file_id      = i_case_file_id
                  and a.person_id         = v_curr_person
                  and a.person_type      <> 'U'
                  and a.active_flag       = 'Y'
              )
           then  'Y'
           else  'N'
        end
      into 
        v_is_participant
      from 
        dual
      ;

      IF v_is_participant = 'Y'
      THEN
          RETURN 0;
      END IF;

      v_quarantine_ok := 'N';
      v_finalise_ok   := 'N';

      open user_privs;

      loop
          fetch user_privs into v_single_priv,
                                v_profile_org_unit,
                                v_local_role;  

          exit when user_privs%notfound;

          IF v_single_priv = QUARANTINED_ACCESS
          THEN 
               v_quarantine_ok := 'Y';
               continue;
          END IF;

          IF v_single_priv = FINALISED_ACCESS
          THEN 
               v_finalise_ok := 'Y';
               continue;
          END IF;

          IF bitand(v_single_priv, ORG_CASCADE) <> 0 
          THEN
              select 
                case
                  when i_mgr_org_unit in (
                    select 
                      a.org_unit_child
                    from
                      org_rel a
                    connect by nocycle
                      a.org_rel_type_code = CHS_ORG_TREE and 
                    prior 
                      a.org_unit_child = a.org_unit_parent
                    start with 
                      a.org_unit_child = v_profile_org_unit
                  and a.org_rel_type_code = CHS_ORG_TREE)
                  then v_single_priv
                  else 0
                end
              into 
                v_single_priv
              from 
                dual
              ;

          END IF;

          IF bitand(v_single_priv, CASE_SPECIFIC) <> 0 
          THEN
              IF v_local_role = 'CA'
              THEN
                select 
                  case
                    when exists 
                        (select
                                *
                           from
                                case_assistant a
                          where
                                a.case_file_id      = i_case_file_id
                            and a.case_assistant_id = v_curr_person
                            and sysdate between       a.access_from and a.access_to
                          )
                    then  v_single_priv
                    else  0
                    end
                into 
                  v_single_priv
                from 
                  dual
                ;
                IF v_single_priv <> 0 
                THEN
                    v_quarantine_ok := 'Y';
                END IF;
              ELSE
                  IF v_curr_person <> i_dco_person_id
                  THEN 
                      v_single_priv := 0;
                  END IF;
              END IF;
          END IF;

          o_access_granted := (o_access_granted + v_single_priv - bitand(o_access_granted, v_single_priv));

      end loop;

      close user_privs;

      IF o_access_granted = 0 THEN    
        RETURN o_access_granted;
      END IF;

      IF (v_quarantine_ok = 'N' AND (i_dco_person_id <> v_curr_person
                                 OR  BITAND(o_access_granted,CASE_SPECIFIC) = 0)) THEN
        select 
          case
            when exists 
                (select
                        *
                   from
                        quarantine a
                  where
                        a.case_file_id      = i_case_file_id
                    and a.active_flag       = 'Y'
                  )
            then  0
            else  o_access_granted
          end
        into 
          o_access_granted
        from 
          dual
        ;
      END IF;

      IF o_access_granted = 0 THEN    
        RETURN o_access_granted;
      END IF;

      IF v_finalise_ok = 'N' THEN
        select 
          case
            when exists 
                (select
                        *
                   from
                        finalise a
                  where
                        a.case_file_id      = i_case_file_id
                  )
            then  0
            else  o_access_granted
          end
        into 
          o_access_granted
        from 
          dual
        ;

      END IF;

      IF v_finalise_ok = 'Y' THEN
        select 
          case
            when exists 
                (select
                        *
                   from
                        finalise a
                  where
                        a.case_file_id      = i_case_file_id
                  )
            then  BITAND(o_access_granted, READ_ONLY)
            else  o_access_granted
          end
        into 
          o_access_granted
        from 
          dual
        ;

      END IF;

      RETURN o_access_granted;

    END check_case_access;    

    FUNCTION decode_role(i_case_file_id IN INTEGER, i_mgr_org_unit IN INTEGER, i_dco_person_id in varchar2)
      RETURN VARCHAR2
      DETERMINISTIC
    IS

      v_curr_person      varchar2(8) := SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER');
      v_access_granted   INTEGER     := 0;
      o_role_used        access_role.role_code%type;

    BEGIN

      v_access_granted := check_case_access(i_case_file_id, i_mgr_org_unit, i_dco_person_id);

      IF BITAND(v_access_granted, READ_CASE_ORG_UNITS ) <> 0 THEN
          IF v_curr_person = i_dco_person_id THEN
              o_role_used := ROLE_DCO;
          ELSE
              o_role_used := ROLE_CA;
          END IF;
      ELSE 
          IF BITAND(v_access_granted, READ_GROUP_ORG_UNITS) <> 0 THEN
              o_role_used := ROLE_HOU;
          ELSE
              IF BITAND(v_access_granted, READ_WORLD_ORG_UNITS) <> 0 THEN
                  select 
                    case
                    when exists 
                        (select
                                *
                           from
                                access_profile a
                          where
                                a.person_id       = v_curr_person
                            and a.role_code       = ROLE_CRUM
                          )
                    then  ROLE_CRUM
                    else  ROLE_CRUO
                  end
                into 
                  o_role_used
                from 
                  dual
                ;
              END IF;
          END IF;
      END IF;

      RETURN o_role_used;

    END decode_role;

    FUNCTION default_priv_mask(i_person_id in varchar2) 
      RETURN INTEGER
      DETERMINISTIC
    IS

      o_access_available INTEGER     := 0;
      v_single_priv      INTEGER     := 0;

      cursor user_privs is
        select 
               d.priv_id
        from   
               access_user      a
              ,access_profile   b
              ,access_role      c
              ,access_role_priv d
              ,access_priv      e
        where  
               a.person_id      = i_person_id 
          and  a.active_flag    = 'Y'
          and  b.person_id      = a.person_id
          and  c.role_code      = b.role_code
          and  d.role_code      = b.role_code
          and  e.priv_id        = d.priv_id
      ;

    BEGIN

      open user_privs;

      loop
          fetch user_privs into v_single_priv;

          exit when user_privs%notfound;

          o_access_available := (o_access_available + v_single_priv - bitand(o_access_available, v_single_priv));

      end loop;

      close user_privs;

      RETURN o_access_available;

    END default_priv_mask;    

END chs_security_policies;

/

BEGIN
  DBMS_RLS.ADD_POLICY (object_schema     => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_READ',
                       function_schema   => 'CHS',
                       statement_types   => 'SELECT',
                       policy_function   => 'chs_security_policies.case_file_read');

  DBMS_RLS.ADD_POLICY (object_schema     => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_WRITE',
                       function_schema   => 'CHS',
                       statement_types   => 'UPDATE,DELETE',
                       policy_function   => 'chs_security_policies.case_file_write');

  DBMS_RLS.ADD_POLICY (object_schema     => 'CHS',
                       object_name       => 'CASE_FILE',
                       policy_name       => 'CASE_FILE_REGISTER',
                       function_schema   => 'CHS',
                       statement_types   => 'INSERT',
                       policy_function   => 'chs_security_policies.case_file_register');
END;

【讨论】:

以上是关于向用户 Oracle 授予更新的主要内容,如果未能解决你的问题,请参考以下文章

在用户只能访问与其 id 列相关的列的条件下向用户授予选择列权限 - Oracle pl/sql

通过 rails 向 mongo 用户授予角色

oracle怎么创建用户和授予权限

oracle 创建用户授予权限问题

oracle怎么创建用户和授予权限?

oracle 创建用户怎么授予创建数据库的权限