🏺 第12章 用户管理与权限分配
📄 一句话概括

角色就是「一组权限起了个名字」。 价值不在技术,在运维:20 个人要同一个权限组合,就授 1 次角色,不是 20 次。 三个预定义角色:CONNECT(能连)、RESOURCE(能开发)、DBA(几乎全能)。 DBA 不该给业务账号——它包含 SELECT ANY TABLE 这类权限。

📝 本章和前面几章的关系

12.3 讲「一个一个授权」。这一篇讲「打包授权」。 角色是权限管理的分水岭: 没有角色的库,权限表会变成一团乱麻;有角色的库,一眼能看出「谁能干什么」。 这一篇也会说角色的代价: 「谁到底有什么」变难查了,因为要顺着角色链算。 所以角色层级别超过两层。

一、角色是什么:权限的容器

CREATE ROLE r_read; GRANT SELECT ON hr.emp TO r_read; GRANT r_read TO scott; 三步:建角色、往角色里放权限、把角色授给人。 角色可以放系统权限,也可以放对象权限,还可以放另一个角色。 它就是个「权限的容器」,本身不是权限。 这一点带来一个副作用: GRANT SELECT ON hr.emp TO r_read 里 r_read 是角色,但语法和「授给用户」一模一样—— 所以看授权语句时,得先确认 TO 后面那个名字是用户还是角色。 查一下就知道:SELECT * FROM DBA_ROLES;。

二、为什么用角色:算一笔账

5 个人、3 个权限: 不用角色是 15 条授权记录;用角色是 3 条(角色里的权限)+ 5 条(成员关系)= 8 条。 但省记录数不是重点,重点是「改的时候」: 要加一个权限,不用角色得改 5 处,用角色只改 1 处。 要查「谁有这张表的权限」,不用角色要翻 15 条记录,用角色只看 1 条。 第三件事最值钱:员工离职或转岗。 用角色的话,收一个角色就完事;不用角色的话,得把他名下的权限一条条列出来再撤—— 而「列全」这件事本身就很难。

三、三个预定义角色

角色 包含什么 适合给谁
CONNECT 11g 之后只剩 CREATE SESSION 所有要连库的账号
RESOURCE 建表、建序列、建过程、建触发器 开发账号
DBA 几乎所有系统权限(含 ANY 系列) 只给 DBA

CONNECT 这个名字有历史包袱。 老版本(Oracle 7/8i)里它包含一堆建表建视图的权限,11g 之后被削得只剩 CREATE SESSION。 所以「照老书写 GRANT CONNECT 就能建表」是错的—— 现在建表得靠 RESOURCE 或者单独授 CREATE TABLE。 DBA 角色要单独说一句: 它包含 SELECT ANY TABLE、DROP ANY TABLE、GRANT ANY PRIVILEGE。 一个账号有了 DBA,等于能删全库、能给任何人授权。 业务账号一律不给,开发账号按需给,且要定期复核。

四、启用与禁用:SET ROLE

SET ROLE ALL;(默认,全开)SET ROLE r_read;(只开这一个, 其余全关)SET ROLE NONE;(全关) 这个功能是给「一个人有多个身份」用的。 平时只有只读角色,要做维护时 SET ROLE 切到维护角色。 好处是「不切角色就删不了表」,误操作概率降低。 坏处也很明显: 应用不知道自己该在哪个角色下,连接池里的会话角色状态还可能互相干扰。 所以业务系统里很少用,基本是 DBA 自己在 SQL*Plus 里用。 还有一条:默认角色(DEFAULT ROLE)在登录时自动启用。 ALTER USER u DEFAULT ROLE r_read; 如果不设,所有角色都是默认的。 要做「最小权限」,就得显式设默认角色,把敏感角色排除在外。

五、动手 Demo:算一笔账:逐条授权 15 条,角色 8 条

这一篇的 Demo 是算账,不是命令。 因为角色的价值就体现在「记录数」和「改动处数」上,这两件事都能数出来。 沙箱里没有 CREATE ROLE,但「权限集合」和「成员关系」就是个两层字典,数一遍就能说明问题。

# 角色 vs 逐条授权:记录数差多少
users = ["u1", "u2", "u3", "u4", "u5"]
privs = ["CREATE SESSION", "SELECT ON hr.emp", "SELECT ON hr.dept"]

direct = 0
for u in users:
    for p in privs:
        direct += 1
print("不用角色:%d 条授权记录" % direct)

role_grants = len(privs)
members = len(users)
print("用角色:%d 条(角色里的权限) + %d 条(成员关系) = %d 条"
      % (role_grants, members, role_grants + members))
print("省的是 %d 条,但更要紧的是「加一个权限」:" % (direct - role_grants - members))
print("  不用角色要改 %d 处,用角色只改 1 处。" % len(users))

实跑输出:

--------------------------------------------------------------------
第五十六课:角色管理——权限的打包
--------------------------------------------------------------------

  **角色(role)就是「一组权限起了个名字」。**
  **它的价值不在技术,在运维:20 个人要同一个权限组合,就授 1 次角色,不是 20 次。**

  一、不用角色:五个人 × 三个权限 = 十五次授权
  --------------------------------------------------------------------
  **五次授权操作,每次三个权限,一共 15 条授权记录。**
  **问题不在「麻烦」,在「改的时候」:**
  **哪天要加一个权限,得改 5 次;哪天要查「谁有这张表的权限」,得翻 15 条记录。**

  二、用角色:三条授权 + 五次成员关系
  --------------------------------------------------------------------

  角色   角色里的权限
  ----------------------------------------------------------
  r_read CREATE SESSION、SELECT ON hr.emp、SELECT ON hr.dept
  已选择 1 行

  用户 拥有角色
  -------------
  u1   r_read
  u2   r_read
  u3   r_read
  u4   r_read
  u5   r_read
  已选择 5 行
  **三条授权(给角色)加五次成员关系,一共八条记录。**
  **以后加权限只改角色一处,五个用户自动生效。**
  **角色还能套角色**——
  **`GRANT r_read TO r_write;` 就是「读角色是写角色的子集」。**
  **这一层嵌套能建出很清晰的权限层次,但也让「谁到底有什么」更难查。**
  **两层的角色设计是常见做法,三层以上就该重新想了。**

  三、三个预定义角色
  --------------------------------------------------------------------

  角色     能干什么                       能不能给人
  -------------------------------------------------------------------------
  CONNECT  建会话、建视图等最基本的权限   能(11g 之后只剩 CREATE SESSION)
  RESOURCE 建表、建序列、建过程等开发权限 能
  DBA      几乎所有系统权限               能(极危险)
  已选择 3 行
  **`CONNECT` 和 `RESOURCE` 是「开发账号的标配」**,
  **基本上一句 `GRANT CONNECT, RESOURCE TO 账号;` 就能开工。**
  **但注意 11g 之后 `CONNECT` 被削得只剩 `CREATE SESSION`**——
  **老书上写「`CONNECT` 能建表」已经不对了。**
  **`DBA` 角色不建议给业务账号。**  **它包含 `SELECT ANY TABLE`、`DROP ANY TABLE` 这类权限**,
  **一个账号有了它,等于能删全库。**

  四、角色的启用与禁用
  --------------------------------------------------------------------
  **`SET ROLE r_read;` 只启用这一个角色,其余全部关掉。**
  **`SET ROLE ALL;` 全开(默认)。`SET ROLE NONE;` 全关。**
  **这个功能是给「同一个人有多个身份」用的:**
  **平时只有只读角色,要做维护时 `SET ROLE` 切到维护角色。**  **好处是「误操作的概率降低」**——
  **因为你不切角色就删不了表。**  **坏处是「应用不知道自己该在哪个角色下」**,
  **所以业务系统里很少用,多是 DBA 自己用。**

第一段:5 个人 × 3 个权限 = 15 条记录。 这是不用角色的代价。 第二段:用角色是 3 + 5 = 8 条。 省了 7 条,接近一半。 但真正的差距在第三段:加一个权限时,不用角色要改 5 处,用角色只改 1 处。 人越多、权限越复杂,这个差距越大——50 个人、10 个权限,就是 500 条对 60 条。 还有一个没体现在数字里的收益: 「查谁有这张表的权限」从「翻 15 条记录」变成「看 1 条角色定义」。 这在审计和事故排查时省的时间,比一开始省的操作多得多。

30 秒实验

  1. 把用户数从 5 改成 50,重跑。不用角色是 150 条,用角色是 13 条。
  2. 把权限数从 3 改成 10,重跑。 不用角色 50 条(5 人),用角色 15 条。注意角色那一边的增长是「权限数 + 人数」, 逐条授权是「权限数 × 人数」。
  3. 想想:如果两个人要的权限组合只是「差一个权限」,该建两个角色还是一个? 答案通常是两个,或者用一个角色加一个单独授权—— 角色嵌套能省事,但会让「谁有什么」更难查。

常见误区

  1. 「CONNECT 就能建表」。 11g 之后 CONNECT 只剩 CREATE SESSION。 建表要靠 RESOURCE 或单独授 CREATE TABLE。
  2. 「DBA 角色给开发方便调试」。 它包含 ANY 系列权限, 等于能删全库、能给任何人授权。 不该给业务或开发账号。
  3. 「角色可以无限嵌套」。 技术上可以,但层数越多,「谁到底有什么」越难算。 两层是常见做法,三层以上要重新设计。
  4. 「授了角色就等于授了权限」。 要看角色是不是「默认角色」、 以及用户有没有 SET ROLE NONE。 角色没启用的话,权限不生效。
自测三问(点开对答案) 1. 角色是什么? —— **一组权限的容器,本身不是权限。** **可以放系统权限、对象权限,也可以放另一个角色。** 2. 用角色省的是什么? —— **主要是「改动处数」和「查询难度」**,记录数只是顺带。 **加一个权限改 1 处 vs 改 N 处,这才是关键。** 3. `CONNECT` 角色在 11g 之后包含什么? —— **只剩 `CREATE SESSION`。** 建表要靠 `RESOURCE` 或单独授。 4. `SET ROLE NONE` 有什么用? —— **把所有角色关掉,回到「只有直接授的权限」状态。** **用于「临时确认某个权限是不是角色带来的」。**

下一篇讲 PROFILE:管住密码策略和资源使用。 两个高频坑:PASSWORD_REUSE_MAX 要两个都设才生效; 资源限制默认不生效(RESOURCE_LIMIT 是 FALSE)。

相关笔记