有一套 Oracle 11GR2 数据库,开发想要针对表中的某些列授权查询,其他列不可查询,按照常规的授权方式是无法针对表中的某些列进行授权查询的,最基础的都需要针对表进行授权。

首先排除网上那些所谓支持列单独授权的言论:

1
2
3
4
5
SQL> grant select on a.test(name) to b;
grant select on a.test(name) to b
*
ERROR at line 1:
ORA-00905: missing keyword

Oracle 目前没有这种写法(测试版本为 11GR2 数据库)。

解决方案

1.最开始想的办法是针对这些列再创建一张表,再将新建表授权给需要访问的用户,然后写一个 job 定时同步这些列的数据到新的表中。(但是这种方式实时性较差,而且总感觉怪怪的)

2.后来换了个思路,将需要查询的列的结果集创建成一个视图(实时查询),然后将视图查询权限授予需要查询的用户,是不是可以呢?

测试过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
-- 针对 A 用户创建表 test,有两个列 id ,name
SQL> create table a.test (id number,name varchar2(20));

Table created.
-- 插入两条数据
SQL> insert into a.test values (1,'a');

1 row created.

SQL> insert into a.test values (2,'b');

1 row created.

SQL> commit;

Commit complete.
-- 连接 B 用户查询 A.TEST 表,没有权限
SQL> conn b/b
Connected.
SQL> select * from a.test;
select * from a.test
*
ERROR at line 1:
ORA-00942: table or view does not exist
-- 切换到 SYS 用户
SQL> conn / as sysdba
Connected.
-- 针对 A.TEST 表中的 NAME 列创建一个视图 A.TEST_NAME
SQL> create view a.test_name as select name from a.test;

View created.
-- 连接 B 用户查询 A.TEST_NAME 视图,没有权限
SQL> conn b/b
Connected.
SQL> select * from a.test_name;
select * from a.test_name
*
ERROR at line 1:
ORA-00942: table or view does not exist

-- 切换到 SYS 用户
SQL> conn / as sysdba
Connected.
-- 授予视图 A.TEST_NAME 查询权限给 B 用户
SQL> grant select on a.test_name to b;

Grant succeeded.
-- 连接 B 用户查询 A.TEST_NAME 视图,可以查到数据
SQL> conn b/b
Connected.
SQL> select * from a.test_name;

NAME
--------------------
a
b
-- 同时,B 用户依然没有查询 A.TEST 基表的权限
SQL> select * from a.test;
select * from a.test
*
ERROR at line 1:
ORA-00942: table or view does not exist

SQL> select id from a.test;
select id from a.test
*
ERROR at line 1:
ORA-00942: table or view does not exist

由此可以验证,第二种方案是完全可行的,甚至表中的部分数据授权访问也可以通过这种方式来实现。