角色与权限(ROLE/GRANT/REVOKE)
本教程共 50 篇 · 第 49 篇 · 更新于 2026-07-31 · 约 8 分钟阅读
49. 角色与权限(ROLE/GRANT/REVOKE)
本节目标:学完你能创建可登录的角色、用 GRANT/REVOKE 分配和回收权限,并理解 PostgreSQL 里「角色即用户」的统一模型。
很多数据库把「用户」和「角色(组)」分开。PostgreSQL 不这么分——它只有一种东西叫角色(ROLE)。一个角色可以是一个人用来登录的账号,也可以是一个权限的集合(组)。区别在于:能不能登录。
换句话说,PG 里「用户」不是一个独立概念,它就是「带 LOGIN 属性的角色」。这套统一模型一开始有点绕,但用顺了会发现权限管理特别干净。
角色就是用户,区别在 LOGIN
CREATE ROLE 创建一个角色。如果带了 LOGIN 属性,它就能连数据库,本质上就是别的系统里说的「用户」。
-- 创建一个不能登录的纯权限组
postgres=# CREATE ROLE app_reader;
-- 创建一个能登录、带密码的账号
postgres=# CREATE ROLE analyst LOGIN PASSWORD 'Analyst@123';
Note
CREATE USER 名字其实等价于CREATE ROLE 名字 LOGIN。PG 里没有独立用户概念,记住「角色 + LOGIN = 用户」就够了。
创建带额外能力的角色也很直接:
postgres=# CREATE ROLE manager LOGIN PASSWORD 'Manager@123' CREATEDB;
常见角色属性(attribute):
LOGIN:能否连接数据库。没有它,这个角色连不上,只能当组用。SUPERUSER:超级用户,绕过一切权限检查(只能由超级用户来授予)。CREATEDB:能否建库。CREATEROLE:能否建/改其他角色。REPLICATION:能否做流复制。PASSWORD:登录密码,可写作PASSWORD 'xxx'或PASSWORD NULL清掉。
Warning
SUPERUSER权限极大,日常业务账号千万别给。需要高级能力时,宁可单独授权,也不要随手设成超级用户。另外密码写在命令行历史里不安全,生产环境建议用\password交互设置。
改角色属性用 ALTER ROLE,删角色用 DROP ROLE:
postgres=# ALTER ROLE analyst PASSWORD 'NewPass@456';
postgres=# ALTER ROLE analyst CREATEDB;
postgres=# DROP ROLE IF EXISTS app_reader;
Tip删角色前,先把它拥有的对象转走或授权给别人,否则 DROP 会报「仍有依赖」。可用
REASSIGN OWNED把对象批量转给别的角色,再 DROP。
GRANT 授权
对象刚建好时,只有它的拥有者和超级用户能碰。要把权限给别人,用 GRANT。
-- 让 analyst 能查 users 表
postgres=# GRANT SELECT ON users TO analyst;
-- 给 app_reader 组在 orders 上的读写权限
postgres=# GRANT SELECT, INSERT, UPDATE ON orders TO app_reader;
-- 给全部权限(谨慎)
postgres=# GRANT ALL PRIVILEGES ON users TO analyst;
表上能授的权限有:SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES、TRIGGER,以及代表全部的 ALL。
列级权限
有时候你只想让人看某几列,比如隐藏用户的邮箱:
postgres=# GRANT SELECT (id, username, age) ON users TO app_reader;
-- 这个角色查 users 只能看到这三列,SELECT email 会报权限错误
也可以只给某几列的 UPDATE 权,其它列动不了:
postgres=# GRANT UPDATE (status) ON orders TO app_reader;
-- app_reader 只能改 orders.status,改别的列会被拒
授权给别人再转授:GRANT OPTION
WITH GRANT OPTION 表示被授权者可以把这个权限再分给别人:
postgres=# GRANT SELECT ON users TO analyst WITH GRANT OPTION;
-- analyst 现在也能 GRANT SELECT ON users TO 别人
REVOKE 回收
给错了就收回来,语法和 GRANT 对称:
postgres=# REVOKE INSERT ON orders FROM app_reader;
如果当初带了 GRANT OPTION,回收时要连选项一起收:
postgres=# REVOKE GRANT OPTION FOR SELECT ON users FROM analyst;
-- 只收回「转授权」,保留 analyst 自己的查询权
数据库级和 schema 级权限
除了表,还有两层常被忽略的权限。
数据库级的 CONNECT 和建表权:
postgres=# GRANT CONNECT ON DATABASE postgres TO app_reader;
postgres=# GRANT CREATE ON DATABASE postgres TO manager;
schema 级的 USAGE,是新手最容易踩的坑:你给了一个角色 SELECT ON users,但他查询时仍然报「权限拒绝」。原因往往是他连 schema 的访问权都没有。schema 像是表所在的文件夹,默认角色对它没有 USAGE 权限就进不去:
postgres=# GRANT USAGE ON SCHEMA public TO app_reader;
Warning权限是层层加码的:先得有数据库的 CONNECT,再得有 schema 的 USAGE,最后才轮到表上的 SELECT/INSERT。哪一层缺了都连不上或读不到。排查权限问题就从这三层依次查。
批量授权整个 schema
一张张表 GRANT 太累。可以一次授权某个 schema 里「当前所有表」:
postgres=# GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_reader;
注意这只是「当前已有的表」。以后新建的表不自动包含,所以还得配 ALTER DEFAULT PRIVILEGES(见下)。
默认权限:让新建对象自动带权
ALTER DEFAULT PRIVILEGES 设定「今后在这个 schema 新建的表,默认给谁什么权」:
postgres=# ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO app_reader;
-- 之后任何人建的新表,app_reader 自动能查
还能对序列、函数分别设默认权:
postgres=# ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE ON SEQUENCES TO app_reader;
角色继承:把角色加进角色
角色可以互相嵌套。把 A 角色授予 B,B 就自动拥有 A 的权限,这叫角色继承(Role Membership)。
-- 让 analyst 也具备 app_reader 的所有权限
postgres=# GRANT app_reader TO analyst;
被继承的角色通常是「组」(NOLOGIN),个人账号继承它,权限管理就清晰很多:要加一类权限,只改组即可。继承还能加 ADMIN 和 INHERIT 选项:
postgres=# GRANT app_reader TO analyst WITH ADMIN OPTION;
-- analyst 也能把 app_reader 再授予别人
GRANT 组 TO 用户 默认带 INHERIT TRUE,即用户自动拥有组权限。也可以显式关掉继承,让用户必须 SET ROLE 才用组权限:
postgres=# GRANT app_reader TO analyst WITH INHERIT FALSE;
-- analyst 不会自动拿到 app_reader 的权限,需先 SET ROLE app_reader
查看现有角色:
postgres=# SELECT rolname, rolcanlogin, rolsuper
FROM pg_roles;
会话里临时「变成」另一个角色用 SET ROLE,方便以组身份操作:
postgres=# SET ROLE app_reader;
-- 当前会话以 app_reader 的权限运行,方便测试
postgres=# RESET ROLE; -- 还原
Tip新建表默认在
public模式。想让某角色以后自动拿到新表的权限,用ALTER DEFAULT PRIVILEGES预设(见上),比一张张 GRANT 省力。
特殊角色 PUBLIC
PUBLIC 不是一个真实角色,而是一个「所有角色(含未来新建的)」的代称。给它授权等于给所有人授权:
postgres=# GRANT SELECT ON users TO PUBLIC;
-- 所有角色,包括以后建的,都能查 users
这把双刃剑要慎用,别把敏感表授权给 PUBLIC。想收回时也用 REVOKE:
postgres=# REVOKE SELECT ON users FROM PUBLIC;
连接层还有一道关:pg_hba.conf
即使角色有 LOGIN 和密码,能不能连上还受 pg_hba.conf 管——它决定「从哪台机器、用哪种方式能连」。比如限制某个角色只能从内网连。这属于实例级安全,日常建角色时先知道有这一层即可,改它要动配置文件并 reload。
Note权限链路是三层:pg_hba.conf(能不能连)→ 数据库 CONNECT + schema USAGE(进不进得去)→ 表/列权限(能干什么)。层层都过才真正读得动数据。
一个完整的小例子
-- 1) 建一个只读组(不能登录)
postgres=# CREATE ROLE report_group;
-- 2) 建一个能登录的人,并让他继承这个组
postgres=# CREATE ROLE alice LOGIN PASSWORD 'Alice@123';
postgres=# GRANT report_group TO alice;
-- 3) 给组授权:能连库、能进 public 模式、能查两张表
postgres=# GRANT CONNECT ON DATABASE postgres TO report_group;
postgres=# GRANT USAGE ON SCHEMA public TO report_group;
postgres=# GRANT SELECT ON users, orders TO report_group;
-- 4) 让今后新建的表也自动对组可读
postgres=# ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO report_group;
-- 5) 后来发现不该让 alice 看 orders
postgres=# REVOKE SELECT ON orders FROM report_group;
Note权限检查是「组 + 个人」叠加的。回收个人从组继承来的某项权限,得用
REVOKE 权限 ON 对象 FROM 组,不是从个人收——个人只是继承了组。
常见误区
- 以为
CREATE ROLE建出来就能登录:不行,必须带LOGIN。 - 只授权表忘授权 schema USAGE:查表照样被拒。
- 把业务账号设成 SUPERUSER「图省事」:后患无穷,权限失控。
- 直接给用户挨个授权:应该建组、让用户继承组,权限才好维护。
- 给 PUBLIC 授权后忘了:等于全员可见,敏感数据要定期排查。
- 用命令行明文写密码:密码会进历史记录,生产用
\password。 - 以为
GRANT ON ALL TABLES管以后新建的表:不管,得配合ALTER DEFAULT PRIVILEGES。