ORACLE中儲存過程的許可權問題

goodlatch發表於2015-03-16
或許你也遇到過同樣的問題:
用sql語句建表沒問題,但是放到儲存過程裡執行就報沒有許可權;
用sql查詢或dml操作也是沒問題,放到儲存過程就報錯許可權不足,或表不存在.

在官方文件上看到有這麼一段話 ,文件地址 

How Roles Work in PL/SQL Blocks
The use of roles in a PL/SQL block depends on whether it is an anonymous block or a named block (stored procedure, function, or trigger), and whether it executes with definer's rights or invoker's rights.
Roles Used in Named Blocks with Definer's Rights
All roles are disabled in any named PL/SQL block (stored procedure, function, or trigger) that executes with definer's rights. Roles are not used for privilege checking and you cannot set roles within a definer's rights procedure.
The SESSION_ROLES view shows all roles that are currently enabled. If a named PL/SQL block that executes with definer's rights queries SESSION_ROLES, then the query does not return any rows.
Roles Used in Named Blocks with Invoker's Rights and Anonymous PL/SQL Blocks
Named PL/SQL blocks that execute with invoker's rights and anonymous PL/SQL blocks are executed based on privileges granted through enabled roles. Current roles are used for privilege checking within an invoker's rights PL/SQL block. You can use dynamic SQL to set a role in the session.


其大意就是說使用者角色的許可權在命名的pl/sql塊裡是不可用的,包括儲存過程、觸發器、函式,但是在匿名的pl/sql塊裡是沒問題的。
什麼是角色的許可權呢?
可以透過dba_roles檢視所有角色:select * from dba_roles;
可以透過user_role_privs及role_sys_privs檢視使用者有那些角色,及角色具有的許可權。 使用者在這兩個檢視中的許可權在儲存過程、觸發器、函式中是不起作用的。


下面演示DDL的實驗,用scott使用者建一個儲存過程來刪除表和建立表

  1. SQL> set linesize 1000
  2. SQL> show user;
  3. USER is "SCOTT"
  4. SQL> col text format a80
  5. SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;

  6.       LINE TEXT
  7. ---------- --------------------------------------------------------------------------------
  8.      1 procedure p_emp1
  9.      2 as
  10.      3 begin
  11.      4 execute immediate 'drop table emp1';
  12.      5 execute immediate 'create table emp1 as select * from emp';
  13.      6 end;

  14. 6 rows selected.

  15. SQL> drop table emp1;

  16. Table dropped.

  17. SQL> create table emp1 as select * from emp;

  18. Table created.

  19. SQL>
  20. SQL> exec p_emp1;
  21. BEGIN p_emp1; END;

  22. *
  23. ERROR at line 1:
  24. ORA-01031: insufficient privileges
  25. ORA-06512: at "SCOTT.P_EMP1", line 5
  26. ORA-06512: at line 1
發現用sql語句直接執行create table emp1 as select * from emp 是沒有問題的,但是在儲存過程中提示許可權不足。
來查一下scott使用者有哪些系統許可權


  1. SQL> select * from session_roles;

  2. ROLE
  3. ------------------------------
  4. CONNECT
  5. RESOURCE

  6. SQL> select * from role_sys_privs order by role;

  7. ROLE             PRIVILEGE                ADM
  8. ------------------------------ ---------------------------------------- ---
  9. CONNECT          CREATE SESSION                NO
  10. RESOURCE         CREATE CLUSTER                NO
  11. RESOURCE         CREATE INDEXTYPE             NO
  12. RESOURCE         CREATE OPERATOR                NO
  13. RESOURCE         CREATE PROCEDURE             NO
  14. RESOURCE         CREATE SEQUENCE                NO
  15. RESOURCE         CREATE TABLE                NO
  16. RESOURCE         CREATE TRIGGER                NO
  17. RESOURCE         CREATE TYPE                NO

  18. 9 rows selected.

  19. SQL> select * from user_sys_privs;

  20. USERNAME         PRIVILEGE                ADM
  21. ------------------------------ ---------------------------------------- ---
  22. SCOTT             UNLIMITED TABLESPACE            NO
scott有CONNECT和RESOURCE兩個角色的許可權,還有一個UNLIMITED TABLESPACE的系統許可權。
接下來,給scott分配create table的許可權,在看看效果


  1. SQL> conn /as sysdba
  2. Connected.
  3. SQL> grant create table to scott;

  4. Grant succeeded.

  5. SQL> conn scott/scott
  6. Connected.
  7. SQL> select * from user_sys_privs;

  8. USERNAME         PRIVILEGE                ADM
  9. ------------------------------ ---------------------------------------- ---
  10. SCOTT             UNLIMITED TABLESPACE            NO
  11. SCOTT             CREATE TABLE                NO

  12. SQL> exec p_emp1;
  13. BEGIN p_emp1; END;

  14. *
  15. ERROR at line 1:
  16. ORA-00942: table or view does not exist
  17. ORA-06512: at "SCOTT.P_EMP1", line 4
  18. ORA-06512: at line 1
  19. --這裡報錯是因為剛剛執行儲存過程的時候已經drop掉emp1表了,但是create時候報錯,所以這是會報表不存在

  20. SQL> create table emp1 as select * from emp;

  21. Table created.

  22. SQL> exec p_emp1;

  23. PL/SQL procedure successfully completed.
給scott分批create table的許可權後,我們可以透過user_sys_privs檢視看到scott擁有的許可權,這時候儲存過程正常了。

*********************************************************************************************************


接下來測試下dml操作,給scott使用者dba的角色,然後讓scott使用者操作test使用者下的表


  1. SQL> conn /as sysdba
  2. Connected.
  3. SQL> grant dba to scott;

  4. Grant succeeded.

  5. SQL> conn scott/scott
  6. Connected.
  7. SQL>
  8. SQL> select * from role_sys_privs order by role;

  9. ROLE             PRIVILEGE                ADM
  10. ------------------------------ ---------------------------------------- ---
  11. CONNECT          CREATE SESSION                NO
  12. DATAPUMP_EXP_FULL_DATABASE CREATE SESSION                NO
  13. DATAPUMP_EXP_FULL_DATABASE CREATE TABLE                NO
  14. DATAPUMP_IMP_FULL_DATABASE ALTER DATABASE                NO
  15. DATAPUMP_IMP_FULL_DATABASE ALTER PROFILE                NO
  16. DATAPUMP_IMP_FULL_DATABASE ALTER RESOURCE COST            NO
  17. DATAPUMP_IMP_FULL_DATABASE ALTER USER                NO
  18. DATAPUMP_IMP_FULL_DATABASE AUDIT ANY                NO
  19. DATAPUMP_IMP_FULL_DATABASE AUDIT SYSTEM                NO
  20. DATAPUMP_IMP_FULL_DATABASE CREATE PROFILE                NO
  21. DATAPUMP_IMP_FULL_DATABASE CREATE SESSION                NO

  22. ROLE             PRIVILEGE                ADM
  23. ------------------------------ ---------------------------------------- ---
  24. DATAPUMP_IMP_FULL_DATABASE DELETE ANY TABLE             NO
  25. DATAPUMP_IMP_FULL_DATABASE EXECUTE ANY OPERATOR            NO
  26. DATAPUMP_IMP_FULL_DATABASE GRANT ANY OBJECT PRIVILEGE        NO
  27. DATAPUMP_IMP_FULL_DATABASE GRANT ANY PRIVILEGE            NO
  28. DATAPUMP_IMP_FULL_DATABASE GRANT ANY ROLE                NO
  29. DATAPUMP_IMP_FULL_DATABASE SELECT ANY TABLE             NO
  30. DBA             ADMINISTER ANY SQL TUNING SET        YES
  31. DBA             ADMINISTER DATABASE TRIGGER        YES
  32. DBA             ADMINISTER RESOURCE MANAGER        YES
  33. DBA             ADMINISTER SQL MANAGEMENT OBJECT     YES
  34. DBA             ADMINISTER SQL TUNING SET        YES
  35. ...
  36. --下邊有很多就不顯示了,我們可以看到dba角色的許可權已經有了


  37. SQL> set linesize 100
  38. SQL> desc test.t;
  39.  Name                         Null?    Type
  40.  ----------------------------------------------------- -------- ------------------------------------
  41.  ID                                NUMBER

  42. SQL> select * from test.t;

  43.     ID
  44. ----------
  45.      1

  46. SQL>

  47. SQL> select line,text from user_source where type='PROCEDURE' and name='P_INSERT_T' ORDER BY LINE;

  48.       LINE TEXT
  49. ---------- --------------------------------------------------------------------------------
  50.      1 procedure p_insert_t as
  51.      2 begin
  52.      3 insert into test.t values (2);
  53.      4 end;

  54. SQL> insert into test.t values (2);   --可以看到直接insert是沒有問題的

  55. 1 row created.

  56. SQL> select * from test.t;

  57.     ID
  58. ----------
  59.      1
  60.      2

  61. SQL> rollback;

  62. Rollback complete.

  63. SQL> exec p_insert_t;
  64. BEGIN p_insert_t; END;

  65.       *
  66. ERROR at line 1:
  67. ORA-06550: line 1, column 7:
  68. PLS-00905: object SCOTT.P_INSERT_T is invalid
  69. ORA-06550: line 1, column 7:
  70. PL/SQL: Statement ignored

  71. --這裡報了sql無效,我們編譯下儲存過程看看報什麼錯誤

  72. SQL> alter procedure p_insert_t compile;

  73. Warning: Procedure altered with compilation errors.

  74. SQL> show errors;
  75. Errors for PROCEDURE P_INSERT_T:

  76. LINE/COL ERROR
  77. -------- -----------------------------------------------------------------
  78. 3/3     PL/SQL: SQL Statement ignored
  79. 3/20     PL/SQL: ORA-00942: table or view does not exist
  80. --這裡報表不存在,說明沒有對test使用者的t表的select許可權,我們來賦下許可權
  1. SQL>
  2. SQL> conn test/test
  3. Connected.
  4. SQL> grant select on t to scott;

  5. Grant succeeded.

  6. SQL> conn scott/scott
  7. Connected.
  8. SQL> alter procedure p_insert_t compile;

  9. Warning: Procedure altered with compilation errors.

  10. SQL> show errors;
  11. Errors for PROCEDURE P_INSERT_T:

  12. LINE/COL ERROR
  13. -------- -----------------------------------------------------------------
  14. 3/3     PL/SQL: SQL Statement ignored
  15. 3/20     PL/SQL: ORA-01031: insufficient privileges
  16. --這時候開始報沒有insert許可權,繼續賦權
  17. SQL>
  18. SQL>
  19. SQL> conn test/test
  20. Connected.
  21. SQL> grant insert on t to scott;

  22. Grant succeeded.

  23. SQL> conn scott/scott
  24. Connected.
  25. SQL> alter procedure p_insert_t compile;

  26. Procedure altered.

  27. SQL> select * from test.t;

  28.     ID
  29. ----------
  30.      1

  31. SQL> exec p_insert_t;

  32. PL/SQL procedure successfully completed.

  33. SQL> select * from test.t;

  34.     ID
  35. ----------
  36.      1
  37.      2
  38. --最後我們查下scott都有那些表才操作許可權
  39. SQL> select * from user_tab_privs;

  40. GRANTEE          OWNER             TABLE_NAME         GRANTOR             PRIVILEGE                 GRA HIE
  41. ------------------------------ ------------------------------ ------------------------------ ------------------------------ ---------------------------------------- --- ---
  42. SCOTT             TEST             T              TEST             INSERT                 NO NO
  43. SCOTT             TEST             T              TEST             SELECT                 NO NO

 所以在處理儲存過程的時候要注意這些許可權問題,不要只看使用者的角色。

******************************************************************************************************************

我們總是想偷偷懶,每次都要賦許可權感覺好麻煩,有沒有其他好辦法呢?答案是:有。oracle提供了一個authid的屬性

  1. SQL> conn /as sysdba
  2. Connected.
  3. SQL> revoke create table from scott;

  4. Revoke succeeded.

  5. SQL> conn scott/scott
  6. Connected.

  7. SQL> select * from user_sys_privs;

  8. USERNAME         PRIVILEGE                ADM
  9. ------------------------------ ---------------------------------------- ---
  10. SCOTT             UNLIMITED TABLESPACE            NO

  11. SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;

  12.       LINE TEXT
  13. ---------- --------------------------------------------------------------------------------
  14.      1 procedure p_emp1
  15.      2 authid CURRENT_USER  --注意這裡,多了一句
  16.      3 as
  17.      4 begin
  18.      5 execute immediate 'drop table emp1';
  19.      6 execute immediate 'create table emp1 as select * from emp';
  20.      7 end;

  21. 7 rows selected.

  22. SQL> exec p_emp1;

  23. PL/SQL procedure successfully completed.

新增一個authid CURRENT_USER就可以了,當然這麼做也有一點風險,就是如果scott和test使用者都有一個emp表,那麼當test使用者執行的時候,新建的emp1表會在test使用者下


  1. SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;

  2.       LINE TEXT
  3. ---------- --------------------------------------------------------------------------------
  4.      1 procedure p_emp1
  5.      2 authid CURRENT_USER
  6.      3 as
  7.      4 begin
  8.      5 execute immediate 'create table emp1 as select * from emp'; --這裡我們去掉了drop的語句
  9.      6 end;

  10. 6 rows selected.

  11. SQL> conn / as sysdba
  12. Connected.
  13. SQL>
  14. SQL>
  15. SQL> select owner,table_name from dba_tables where table_name='EMP1';

  16. OWNER             TABLE_NAME
  17. ------------------------------ ------------------------------
  18. SCOTT             EMP1

  19. SQL> drop table scott.emp1;

  20. Table dropped.

  21. SQL> grant resource to test;

  22. Grant succeeded.

  23. SQL> grant execute on scott.p_emp1 to test;

  24. Grant succeeded.

  25. SQL> conn test/test;
  26. Connected.
  27. SQL> create table emp (id number) ;

  28. Table created.

  29. SQL> exec scott.p_emp1;

  30. PL/SQL procedure successfully completed.

  31. SQL> conn /as sysdba
  32. Connected.

  33. SQL> select owner,table_name from dba_tables where table_name='EMP1';

  34. OWNER             TABLE_NAME
  35. ------------------------------ ------------------------------
  36. TEST             EMP1

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29339009/viewspace-1462017/,如需轉載,請註明出處,否則將追究法律責任。

相關文章