CREATE ROLE 最易漏掉 NOT IDENTIFIED 和 IDENTIFIED BY;不加则11g默认不可授予,12c+虽默认NOT IDENTIFIED但显式声明更安全可靠。
CREATE ROLE 语法里最容易漏掉的两个关键词
oracle 中 create role 默认创建的是“普通角色”,它不能被授予给其他角色,也不能跨 pdb(在多租户环境中)自动继承。如果你后续想用 grant role_name to role_name 做角色嵌套,或者希望角色在应用连接时默认生效,必须显式加上 not identified 或 identified by —— 即使你并不打算用密码激活它。
常见错误现象:ORA-01923(角色已存在但无法被授予)、ORA-01932(管理员权限不足,实则是角色未声明可被授予)。根本原因常是忘了加 NOT IDENTIFIED,导致角色被创建为“不可授予”类型。
-
CREATE ROLE app_reader NOT IDENTIFIED:推荐写法,明确支持角色嵌套和 GRANT TO ROLE -
CREATE ROLE app_reader IDENTIFIED BY pwd123:仅当你需要密码激活(比如通过SET ROLE手动启用)才用 - 不加任何
IDENTIFIED子句 → Oracle 默认创建为NOT IDENTIFIED,但这是 12c+ 的行为;11g 及更早版本会创建为“不可授予”角色,兼容性风险高
批量授予权限时,SYS.DBMS_SQL 不是好选择
有人想用 DBMS_SQL 动态拼 SQL 给多个对象授相同权限,结果触发大量硬解析、权限检查开销,还容易因引号/空格出错。真正高效且安全的做法,是用数据字典视图生成授权语句,再统一执行。
使用场景:给 50 张表统一授予 SELECT,或把某用户下所有 PROCEDURE 的 EXECUTE 授给一个角色。
- 先查出目标对象:
SELECT 'GRANT SELECT ON ' || owner || '.' || table_name || ' TO app_reader;' FROM dba_tables WHERE owner = 'APP_SCHEMA' AND status = 'VALID' - 用
SPOOL或客户端导出为脚本,人工审核后再@grant_script.sql执行 - 避免用
EXECUTE IMMEDIATE在循环里反复调用GRANT:每次都会触发完整的权限校验与审计日志写入,性能差且难追溯 - 注意
dba_tab_privs和dba_role_privs区分“对象权限”和“角色权限”,别混用
角色启用状态(ENABLED)比你想象中更脆弱
即使你把 app_reader 授给了用户,并且用户登录后能 SELECT,也不代表该角色始终生效——Oracle 默认只在会话初始化时检查 DEFAULT ROLE,之后如果 DBA 执行了 ALTER USER ... DEFAULT ROLE NONE,或用户自己执行了 SET ROLE NONE,角色就静默失效了。
性能影响不大,但排查时极易误判:明明 GRANT 过了,SELECT 却报 ORA-00942(表或视图不存在),其实是角色没启用,导致对象不可见。
- 检查当前会话启用的角色:
SELECT * FROM session_roles - 确保角色设为默认:
ALTER USER app_user DEFAULT ROLE app_reader - 如果应用用连接池(如 UCP、Druid),某些驱动会在连接复用时不清除角色状态,导致前一个用户的
SET ROLE影响下一个用户 —— 此时应在连接获取后显式执行SET ROLE app_reader
回收权限时,CASCADE 不等于“连子角色一起删”
DROP ROLE 本身不会级联删除依赖它的权限,但 REVOKE 有隐含行为:如果某个权限是通过角色 A 授予的,而你只对用户执行 REVOKE 角色 A,那用户失去的是整个角色包含的所有权限;但如果角色 A 被其他角色 B 依赖,B 并不会因此失效 —— Oracle 不维护角色依赖图谱。
容易踩的坑是以为 REVOKE app_reader FROM app_user 就万事大吉,结果发现用户还能查表,原因是:表权限曾被直接授予过该用户(GRANT SELECT ON t TO app_user),和角色无关。
- 查直接授给用户的对象权限:
SELECT * FROM dba_tab_privs WHERE grantee = 'APP_USER' - 查该用户拥有的角色:
SELECT granted_role FROM dba_role_privs WHERE grantee = 'APP_USER' - 回收前务必确认是否要同时清理直接授予的权限,否则权限残留会导致最小权限原则失效
-
DROP ROLE后,原角色名可立即重用,但之前基于它的GRANT记录仍保留在数据字典中(DBA_ROLE_PRIVS里对应行消失,但DBA_SYS_PRIVS等不受影响)
角色管理真正的复杂点不在创建或授权,而在权限生命周期的可见性:你很难一眼看出“这个用户到底能访问哪些表”,因为路径可能是用户 → 角色A → 角色B → 对象权限,中间任意一环都可能被单独修改或禁用。别依赖记忆,定期用 SELECT * FROM role_role_privs 和 session_privs 验证实际生效链路。










