砍了个木头2026
121.0MB · 2026-03-04
在上一篇《KingbaseES实战:深度解析用户、会话与连接控制》中,我们探讨了如何控制谁能进入数据库。但进入之后呢?一个用户能否查询某表?能否在某模式中创建新表?这些进入数据库后的行为控制,正是本文要深度解析的对象访问权限管理。
金仓数据库的权限体系遵循“最小权限原则”。一个用户或角色连接到数据库后,默认情况下,除了拥有者(Owner)或超级用户,没有任何操作其他对象的权限。
对象权限的三层模型:
CONNECT)、能否在库中创建临时表(TEMP/TEMPORARY)、能否在库中创建模式(CREATE)USAGE)、能否在模式中创建对象(CREATE)SELECT、INSERT、UPDATE、DELETE、EXECUTE等对象的创建者自动成为拥有者,拥有该对象的“生杀大权”(DROP、GRANT、REVOKE)。这些特殊权限是隐式的,无法被授予或撤销。
重要概念:在KingbaseES中,每个数据库都有一个默认的public模式。当我们创建一个新数据库时,系统会自动在该数据库中创建一个名为public的模式。这个模式最初属于数据库的创建者(通常是system),并且默认情况下,PUBLIC角色(即所有用户)在该模式中拥有USAGE和CREATE权限。
我们将模拟一个名为 edu_platform 的在线教育平台数据库,进行完整的权限管理操作。
-- 以系统管理员SYSTEM连接数据库
[kingbase@node1 ~]$ ksql -Usystem -dtest
-- 1. 创建业务数据库edu_platform
CREATE DATABASE edu_platform;
-- 2. 切换到edu_platform数据库
c edu_platform system
-- 3. 创建测试用户
CREATE USER instructor_li PASSWORD 'Kingbase_123'; -- 讲师李老师
CREATE USER student_zhang PASSWORD 'Kingbase_123'; -- 学生张同学
CREATE USER ta_wang PASSWORD 'Kingbase_123'; -- 助教王助教
-- 4. 创建业务模式与对象
GRANT CONNECT ON DATABASE edu_platform TO instructor_li; --授予连接数据库的权限给instructor_li
CREATE SCHEMA course_schema; -- 课程模式
ALTER SCHEMA course_schema OWNER TO instructor_li; --将模式的拥有权转移给instructor_li
-- 创建课程表和选课记录表
CREATE TABLE course_schema.course_list (
course_id INT PRIMARY KEY,
course_name VARCHAR(100),
instructor VARCHAR(50)
);
CREATE TABLE course_schema.enrollment (
enroll_id INT PRIMARY KEY,
student_name VARCHAR(50),
course_id INT,
enroll_date DATE
);
ALTER TABLE course_schema.course_list OWNER TO instructor_li; --将表的拥有者变更为instructor_li
ALTER TABLE course_schema.enrollment OWNER TO instructor_li; --将表的拥有者变更为instructor_li
-- 插入测试数据
c edu_platform instructor_li
INSERT INTO course_schema.course_list VALUES (1, '数据库内核解析', '李老师');
INSERT INTO course_schema.course_list VALUES (2, 'Linux系统调优', '王老师');
INSERT INTO course_schema.enrollment VALUES (1, '张同学', 1, CURRENT_DATE);
助教 ta_wang 需要查看课程列表和选课情况,但不能修改任何数据。
-- 1. 授予连接数据库的权限
GRANT CONNECT ON DATABASE edu_platform TO ta_wang;
-- 2. 授予使用模式的权限
GRANT USAGE ON SCHEMA course_schema TO ta_wang;
-- 3. 授予表的SELECT权限
GRANT SELECT ON course_schema.course_list TO ta_wang;
GRANT SELECT ON course_schema.enrollment TO ta_wang;
-- 4. 验证
c edu_platform ta_wang
SELECT * FROM course_schema.course_list; -- 成功
INSERT INTO course_schema.course_list VALUES (3, 'SQL优化', '赵老师'); -- 失败!权限不足
-- 5. 权限查询
edu_platform=# l edu_platform
数据库列表
名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | ICU 排序 | 存取权限
--------------+--------+----------+-------------+-------------+----------+------------------------
edu_platform | system | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | | =Tc/system +
| | | | | | system=CTc/system +
| | | | | | instructor_li=c/system+
| | | | | | ta_wang=c/system
(1 行记录)
edu_platform=# dn+ course_schema
架构模式列表
名称 | 拥有者 | 存取权限 | 描述
---------------+--------+------------------+------
course_schema | system | system=UC/system+|
| | ta_wang=U/system |
(1 行记录)
edu_platform=# dp+ course_schema.*
存取权限
架构模式 | 名称 | 类型 | 存取权限 | 列特权 | 策略
---------------+-------------+--------+------------------------+--------+------
course_schema | course_list | 数据表 | system=arwdDxtp/system+| |
| | | ta_wang=r/system | |
course_schema | enrollment | 数据表 | system=arwdDxtp/system+| |
| | | ta_wang=r/system | |
(2 行记录)
讲师 instructor_li 需要对自己课程表和选课记录有完全的增删改查权限。由于他是表的拥有者,这些权限默认就有。我们来看如何将表的“部分权限”授予他人。
-- 授予对特定列的UPDATE权限
c edu_platform instructor_li
GRANT UPDATE (student_name, course_id) ON course_schema.enrollment TO ta_wang;
-- 验证
c edu_platform ta_wang
UPDATE course_schema.enrollment SET student_name = '张小凡' WHERE enroll_id = 1; -- 成功
UPDATE course_schema.enrollment SET enroll_date = '2026-01-01' WHERE enroll_id = 1; -- 失败!因为未授予enroll_date列的UPDATE权限。
-- 权限查询
edu_platform=> dp+ course_schema.enrollment
存取权限
架构模式 | 名称 | 类型 | 存取权限 | 列特权 | 策略
---------------+------------+--------+--------------------------------------+---------------------------+------
course_schema | enrollment | 数据表 | instructor_li=arwdDxtp/instructor_li+| student_name: +|
| | | ta_wang=r/instructor_li | ta_wang=w/instructor_li+|
| | | | course_id: +|
| | | | ta_wang=w/instructor_li |
(1 行记录)
学生 student_zhang 需要能查看课程列表,并能向 enrollment 表插入自己的选课记录。
c edu_platform system
GRANT CONNECT ON DATABASE edu_platform TO student_zhang;
GRANT USAGE ON SCHEMA course_schema TO student_zhang;
GRANT SELECT ON course_schema.course_list TO student_zhang;
-- 授予INSERT权限
GRANT INSERT ON course_schema.enrollment TO student_zhang;
c edu_platform student_zhang
SELECT * FROM course_schema.course_list; -- 成功
INSERT INTO course_schema.enrollment (enroll_id, student_name, course_id, enroll_date)
VALUES (2, '张同学', 2, CURRENT_DATE); -- 成功
-- 权限查询
edu_platform=# l edu_platform
数据库列表
名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | ICU 排序 | 存取权限
--------------+--------+----------+-------------+-------------+----------+------------------------
edu_platform | system | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | | =Tc/system +
| | | | | | system=CTc/system +
| | | | | | instructor_li=c/system+
| | | | | | ta_wang=c/system +
| | | | | | student_zhang=c/system
(1 行记录)
edu_platform=# dp+ course_schema.course_list
存取权限
架构模式 | 名称 | 类型 | 存取权限 | 列特权 | 策略
---------------+-------------+--------+--------------------------------------+--------+------
course_schema | course_list | 数据表 | instructor_li=arwdDxtp/instructor_li+| |
| | | ta_wang=r/instructor_li +| |
| | | student_zhang=r/instructor_li | |
(1 行记录)
edu_platform=# dp+ course_schema.enrollment
存取权限
架构模式 | 名称 | 类型 | 存取权限 | 列特权 | 策略
---------------+------------+--------+--------------------------------------+---------------------------+------
course_schema | enrollment | 数据表 | instructor_li=arwdDxtp/instructor_li+| student_name: +|
| | | ta_wang=r/instructor_li +| ta_wang=w/instructor_li+|
| | | student_zhang=a/instructor_li | course_id: +|
| | | | ta_wang=w/instructor_li |
(1 行记录)
【核心知识点】:在KingbaseES中,所有用户都属于PUBLIC角色。默认情况下,PUBLIC角色拥有一些“过于宽泛”的权限,这是生产环境最大的安全隐患。
每个数据库都有自己的public模式。让我们以刚创建的edu_platform数据库为例,查看其public模式的默认权限:
-- 查看public模式的默认权限
c edu_platform system
edu_platform=# dn+ public
架构模式列表
名称 | 拥有者 | 存取权限 | 描述
--------+--------+------------------+------------------------
public | system | system=UC/system+| standard public schema
| | =UC/system |
(1 行记录)
权限解读:=UC/system表示PUBLIC角色拥有USAGE和CREATE权限,即任何能连接数据库的用户都可以在public模式下创建对象!
-- 查看数据库的默认权限
l edu_platform
名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | 存取权限
--------------+--------+----------+-------------+-------------+------------------------
edu_platform | system | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | =Tc/system +
| | | | | system=CTc/system
权限解读:=Tc/system表示PUBLIC角色拥有TEMP(创建临时表)和CONNECT(连接)权限。
【核心操作】:生产环境回收PUBLIC角色的默认权限
-- 回收PUBLIC在public模式中的所有权限
REVOKE ALL ON SCHEMA public FROM PUBLIC;
-- 回收PUBLIC在数据库中的connect和temp权限
REVOKE CONNECT, TEMP ON DATABASE edu_platform FROM PUBLIC;
-- 验证回收结果
dn+ public
名称 | 拥有者 | 存取权限 | 描述
--------+--------+-------------------------+---------------------
public | system | system=UC/system | standard public schema
l edu_platform
名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | 存取权限
--------------+--------+----------+-------------+-------------+------------------------
edu_platform | system | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | system=CTc/system
-- 注意:"=Tc/system" 已经消失,只剩下具体的用户授权
回收PUBLIC默认权限后,需要按需为特定用户授权:
-- 授予用户ta_wang在public模式中的CREATE权限
GRANT CREATE ON SCHEMA public TO ta_wang;
-- 授予用户student_zhang连接权限
GRANT CONNECT ON DATABASE edu_platform TO student_zhang;
-- 查看授权结果
dn+ public
名称 | 拥有者 | 存取权限 | 描述
--------+--------+-------------------------+---------------------
public | system | system=UC/system+ | standard public schema
| | ta_wang=C/system |
l edu_platform
名称 | 拥有者 | 字元编码 | 校对规则 | Ctype | 存取权限
--------------+--------+----------+-------------+-------------+------------------------
edu_platform | system | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | system=CTc/system+
| | | | | student_zhang=c/system
-- 注意:student_zhang只获得了c(CONNECT)权限,没有TEMP和CREATE权限
search_path(搜索路径)决定了当SQL语句中未指定模式名时,数据库会按照什么顺序去查找对象。理解并正确配置search_path,对于简化SQL书写、避免对象访问歧义至关重要。
KingbaseES的默认search_path:
-- 查看当前search_path
SHOW search_path;
search_path
-----------------
"$user", public
默认值含义:
"$user":优先查找与当前用户名同名的模式(如果存在且用户有USAGE权限)public:然后查找public模式sys_catalog 的特殊地位系统目录模式 sys_catalog 总是被搜索,不管它是否在搜索路径中被提及。
搜索路径的实际规则:
sys_temp_nnn(如果存在)总是最先被搜索(用于表、视图、序列等关系对象)sys_catalog 总是在搜索路径中的任何用户模式之前被搜索search_path 中显式列出的模式按顺序搜索这意味着:
sys_catalog 的优先级始终高于 search_path 中除临时模式外的所有用户模式sys_users 时,数据库会先搜索 sys_catalog,找到系统视图后直接返回-- 方式1:通过系统视图查询(显示当前会话值)
SELECT name, setting, source FROM sys_settings WHERE name='search_path';
name | setting | source
-------------+-----------------+---------
search_path | "$user", public | default
(1 行记录)
-- source字段显示该值来自哪里(配置文件/数据库/用户/会话)
-- 方式2:通过current_setting函数
SELECT current_setting('search_path');
-- 方式3:使用show命令(最常用)
SHOW search_path;
search_path 的设置与其他参数方式一样
| 设置级别 | 命令示例 | 生效范围 | 生效方式 | 验证方法 |
|---|---|---|---|---|
| 数据库级 | ALTER DATABASE ... SET search_path | 该数据库新建立的连接 | 需新建连接生效,已有连接不受影响 | 查看sys_db_role_setting或新建连接验证 |
| 用户级 | ALTER USER ... SET search_path | 该用户新建立的连接 | 需新建连接生效,已有连接不受影响 | 查看sys_db_role_setting或新建连接验证 |
| 用户+数据库级 | ALTER USER ... IN DATABASE ... SET | 特定用户连接特定数据库的新连接 | 需新建连接生效,已有连接不受影响 | 最高优先级,查看sys_db_role_setting |
| 会话级 | SET search_path TO ... | 当前会话 | 立即生效 | SHOW search_path; |
| 实例级 | 修改kingbase.conf文件 | 整个实例的所有连接 | 重启数据库生效 | 查看配置文件或重启后验证 |
1. 数据库级别设置
-- 设置:对 edu_platform 数据库生效
ALTER DATABASE edu_platform SET search_path TO "$user", public, course_schema;
-- 设置后需要重载配置(使设置写入配置文件)
SELECT sys_reload_conf();
-- 验证方式1:查看数据库级别的定制化参数
SELECT * FROM sys_db_role_setting
WHERE setdatabase = (SELECT oid FROM sys_database WHERE datname = 'edu_platform');
-- 验证方式2:新建连接测试(必须)
-- 退出当前连接,重新连接后验证
c edu_platform system
SHOW search_path;
2. 用户级别设置
-- 设置:对 student_zhang 用户生效
ALTER USER student_zhang SET search_path TO "$user", public, course_schema;
-- 验证方式1:查看用户级别的定制化参数
SELECT * FROM sys_db_role_setting
WHERE setrole = (SELECT oid FROM sys_authid WHERE rolname = 'student_zhang');
-- 验证方式2:新建用户连接测试
c edu_platform student_zhang
SHOW search_path;
3. 用户+数据库级别设置(最高优先级)
-- 设置:student_zhang 用户连接 edu_platform 时生效
ALTER USER student_zhang IN DATABASE edu_platform
SET search_path TO "$user", public, course_schema;
-- 重载配置
SELECT sys_reload_conf();
-- 验证:查看特定用户+数据库的定制化参数
SELECT * FROM sys_db_role_setting
WHERE setrole = (SELECT oid FROM sys_authid WHERE rolname = 'student_zhang')
AND setdatabase = (SELECT oid FROM sys_database WHERE datname = 'edu_platform');
4. 会话级别设置(临时测试)
-- 立即生效,仅当前会话有效
SET search_path TO "$user", public, course_schema;
-- 验证
SHOW search_path;
-- 查看所有定制化参数(数据库级、用户级、用户+数据库级)
SELECT
d.datname AS database_name,
r.rolname AS role_name,
s.setconfig
FROM sys_db_role_setting s
LEFT JOIN sys_database d ON s.setdatabase = d.oid
LEFT JOIN sys_authid r ON s.setrole = r.oid;
-- 查看当前会话的search_path及其来源
SELECT
name,
setting,
source -- 显示值来源(配置文件/数据库/用户/会话)
FROM sys_settings
WHERE name = 'search_path';
sys_reload_conf() 的作用:使 ALTER DATABASE/USER 的设置写入配置文件并生效,但只影响新连接在我们构建的edu_platform数据库中,已经回收了public模式的PUBLIC权限,业务表都存储在course_schema模式中。为了让学生student_zhang能够更方便地查询课程表,我们可以配置search_path,让他无需每次都在表名前指定模式名。
-- 当前,student_zhang查询course_list表需要指定模式名
c edu_platform student_zhang
SELECT * FROM course_schema.course_list; -- 需要写模式名,略显繁琐
-- 配置search_path,将course_schema加入搜索路径
c edu_platform system
ALTER USER student_zhang IN DATABASE edu_platform
SET search_path TO "$user", public, course_schema;
SELECT sys_reload_conf();
-- 验证配置
c edu_platform student_zhang
SHOW search_path;
search_path
---------------------
"$user", public, course_schema
-- 现在可以简化SQL书写
SELECT * FROM course_list; -- 自动匹配到course_schema.course_list
SELECT * FROM enrollment; -- 自动匹配到course_schema.enrollment
重要提醒:配置search_path只是简化了SQL书写,并不代表用户自动获得了权限。student_zhang能够查询这些表,是因为我们在“案例3”中已经授予了他相应的SELECT和INSERT权限。权限和搜索路径是两个独立的概念,需要分别配置和验证。
【案例背景】
用户在 public 模式下创建了一张名为 sys_user 的业务表,而 sys_catalog 模式中也存在同名的系统视图。
【问题现象】
执行 SELECT * FROM sys_user; 时,返回的是系统视图 sys_catalog.sys_user 的数据,而非用户期望的业务表。
【原因分析】
根据数据库内核的搜索路径规则:
sys_catalog 总是被优先搜索(除非临时模式存在)sys_user 时,数据库先在 sys_catalog 中找到系统视图并返回public.sys_user 存在,且 public 在 search_path 中,也不会被搜索到【正确解决方案】
1. (推荐)显式指定模式名:
SELECT * FROM public.sys_user; -- 明确查询用户表
2. 避免命名冲突:
在设计业务表时,避免使用 sys_ 开头的名称,以防止与 KingbaseES 系统对象冲突。
【故障现象】
修改search_path为"$user", sys_catalog后,创建表时出现权限错误:
test=# CREATE TABLE t01 (id int);
ERROR: 创建 "sys_catalog.t01" 权限不够
描述: 系统表修改是不被同时允许的
【原因分析】
sys_catalog模式用于存储系统对象,普通用户(甚至system用户)不能在sys_catalog中创建用户表。当search_path设置为"$user", sys_catalog时,创建表时会优先尝试在sys_catalog中创建,从而导致权限错误。
【解决方案】
恢复正确的search_path配置:
-- 修改为正确的search_path
ALTER DATABASE prod SET search_path TO "$user", public;
SELECT sys_reload_conf();
-- 验证
SHOW search_path;
search_path
-----------------
"$user", public
在 KingbaseES 中,所有系统内置的表、视图、函数和扩展对象均采用 sys_ 作为前缀(如 sys_users、sys_class、sys_stat_activity 等)。这些对象由数据库内核或官方扩展管理,是系统运行和监控的基础。
使用 sys_ 前缀命名业务表,不仅会导致查询歧义,还会引发权限管理问题:
sys_catalog 中的系统对象权限由内核管理,普通用户无法也不应修改sys_xxx 系统对象,若业务已使用相同名称,可能导致升级失败或应用异常-- 危险:与系统视图同名
CREATE TABLE sys_users (...);
CREATE VIEW sys_config AS ...;
CREATE FUNCTION sys_get_status();
-- 安全且清晰
CREATE TABLE edu_users (...);
CREATE VIEW course_enrollment_stats AS ...;
CREATE FUNCTION calc_score(...);
edu_、pay_、log_),但不要使用 sys_、pg_、information_schema 等保留前缀配置默认权限,让未来创建的对象自动获得权限,进一步简化权限管理:
-- 设置默认权限:instructor_li未来在course_schema中创建的表,自动授予ta_wang查询权限
c edu_platform instructor_li
ALTER DEFAULT PRIVILEGES IN SCHEMA course_schema
GRANT SELECT ON TABLES TO ta_wang;
-- 测试
CREATE TABLE course_schema.course_feedback (feedback_id int, content text);
dp course_schema.course_feedback
存取权限
架构模式 | 名称 | 类型 | 存取权限 | 列特权 | 策略
---------------+-----------------+--------+--------------------------------------+--------+------
course_schema | course_feedback | 数据表 | instructor_li=arwdDxtp/instructor_li+| |
| | | ta_wang=r/instructor_li | |
(1 行记录)
-- 可以看到ta_wang自动获得了SELECT权限,无需手动授予
-- 检查数据库权限
SELECT has_database_privilege('student_zhang', 'edu_platform', 'CONNECT');
-- 检查模式权限
SELECT has_schema_privilege('student_zhang', 'course_schema', 'USAGE');
-- 检查表权限
SELECT has_table_privilege('ta_wang', 'course_schema.enrollment', 'UPDATE');
-- 检查列权限
SELECT has_column_privilege('ta_wang', 'course_schema.enrollment', 'student_name', 'UPDATE');
-- 查看用户的所有表权限
SELECT * FROM information_schema.table_privileges
WHERE grantee = 'student_zhang';
-- 使用aclexplode解码权限字符串(查看详细权限)
SELECT * FROM aclexplode(
(SELECT relacl FROM sys_class WHERE relname='enrollment')
);
-- 查看当前搜索路径的有效解析结果
SELECT current_schemas(true); -- true表示包含隐式模式(sys_catalog、临时模式等)
SELECT current_schemas(false); -- false表示只返回search_path中显式列出的模式
当用户报告“无法访问某张表”时,按以下顺序排查:
用户能否连接数据库?
SELECT has_database_privilege('username', 'edu_platform', 'CONNECT');
用户能否使用模式?
SELECT has_schema_privilege('username', 'schemaname', 'USAGE');
用户对表有什么权限?
-- 使用aclexplode解码权限字符串
SELECT * FROM aclexplode(
(SELECT relacl FROM sys_class WHERE relname='enrollment')
);
检查search_path配置是否正确
-- 切换到问题用户查看
c edu_platform username
SHOW search_path;
SELECT current_schemas(true); -- 查看实际生效的搜索顺序
检查是否存在同名系统对象冲突
-- 如果表名以sys_开头,尝试显式指定模式名查询
SELECT * FROM public.sys_mytable;
本文通过 edu_platform 数据库的完整案例,系统介绍了 KingbaseES 对象访问权限管理的核心要点:
【必做】回收PUBLIC默认权限
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE CONNECT, TEMP ON DATABASE edu_platform FROM PUBLIC;
分层授权:数据库→模式→对象,逐级授予必要权限
search_path 配置要点
保持默认的 "$user", public 顺序
业务模式可追加在 public 之后:"$user", public, business_schema
不要将 sys_catalog 显式加入 search_path
修改后需新建连接验证:SHOW search_path;、SELECT current_schemas(true);
牢记:search_path 只简化 SQL 书写,不替代权限授予
理解系统目录模式 sys_catalog 的特殊性
public.sys_users)或避免使用 sys_ 前缀务对象利用默认权限:使用ALTER DEFAULT PRIVILEGES为未来对象自动授权
权限诊断:熟练使用has_*_privilege函数、information_schema视图、aclexplode解码
命名规范:避免在业务对象中使用 sys_、pg_ 等系统保留前缀
掌握这些权限管理技能,您就能从“谁能进数据库”的粗粒度控制,提升到“谁能做什么”的精细化管控层面。特别是 PUBLIC 默认权限的回收、search_path 的正确配置和命名规范,是日常运维中需要特别关注的三个关键实践。