第 22 章:用户与角色管理 - PostgreSQL入门

在之前的章节里,我们一直使用 postgres 这个超级管理员账户在操作数据库。这在学习和开发阶段很方便,但在生产环境中,这是极其危险的。postgres 用户拥有至高无上的权力,可以做任何事,包括删掉整个数据库。


一个设计良好的系统,应该遵循最小权限原则 (Principle of Least Privilege)给每个用户或应用程序只授予它完成工作所必需的、最小的权限集合。

为了实现这一点,PostgreSQL 提供了一套强大而灵活的角色 (Role) 系统。

在 PostgreSQL 中,用户和组的概念被统一为了“角色”。一个角色可以是一个数据库用户,也可以是一个用户组,甚至可以两者都是。我们可以创建一个角色,让它拥有一些权限,然后再让其他角色“继承”这个角色的所有权限。这种设计非常优雅和强大。

这一章,我们将学习如何创建角色、管理权限,为我们的数据库建立一个安全可靠的访问控制体系。


22.1CREATE ROLE,CREATE USER

创建角色的基本命令是 CREATE ROLE

-- 创建一个名为 "readonly_group" 的角色,它不能登录,主要用作权限组
CREATE ROLE readonly_group;

-- 创建一个名为 "app_user" 的角色,并赋予它登录权限
CREATE ROLE app_user WITH LOGIN PASSWORD 'a_strong_password';

CREATE ROLE 后面可以跟很多选项,最重要的几个是:

  • LOGIN: 允许这个角色登录到数据库。没有这个属性的角色通常被当作“组”来使用。
  • NOLOGIN: (默认) 不允许登录。
  • PASSWORD '...': 为角色设置一个密码。如果角色有 LOGIN 权限,就必须有密码。
  • SUPERUSER: 超级管理员权限。要非常小心地授予!
  • CREATEDB: 允许创建新的数据库。
  • CREATEROLE: 允许创建、修改、删除其他角色(但不能是超级管理员角色)。

CREATE USER 是什么?
CREATE USER 其实是 CREATE ROLE 的一个别名,它完全等价于:
CREATE ROLE role_name WITH LOGIN;

所以,CREATE USER app_user PASSWORD '...';CREATE ROLE app_user WITH LOGIN PASSWORD '...'; 是一模一样的。使用 CREATE USER 只是在语义上更清晰地表明“我正在创建一个登录用户”。


22.2 权限管理 (GRANT,REVOKE)

创建了角色之后,它默认是没有任何权限的,就像一个空壳子。我们需要用 GRANT 命令来给它“授权”。

GRANT 的语法非常丰富,可以授予各种不同级别的权限。

基本语法:
GRANT privilege ON object_type object_name TO role_name;

  • privilege: 权限类型,如 SELECT, INSERT, UPDATE, DELETE, ALL PRIVILEGES (所有权限), USAGE (用于 Schema 或序列) 等。
  • object_type: 对象类型,如 TABLE, SCHEMA, SEQUENCE, DATABASE, FUNCTION 等。

场景:我们希望 app_user 这个用户,对 orders 表有读写权限,对 users 表只有只读权限。

第一步:授予 orders 表的读写权限

GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE orders TO app_user;

或者用 ALL PRIVILEGES 的简写:

GRANT ALL PRIVILEGES ON TABLE orders TO app_user;

第二步:授予 users 表的只读权限

GRANT SELECT ON TABLE users TO app_user;

第三步:授予 Schema 的使用权限
默认情况下,新用户甚至无法“看到”
public 这个 schema 下的任何表。我们还需要授予 USAGE 权限。

GRANT USAGE ON SCHEMA public TO app_user;

第四步:授予序列 (Sequence) 的使用权限
如果表的主键是
SERIAL 类型,那么 INSERT 操作还需要对应序列的 USAGE 权限,否则无法生成新的 ID。

GRANT USAGE ON SEQUENCE orders_order_id_seq TO app_user;
GRANT USAGE ON SEQUENCE users_user_id_seq TO app_user; -- 如果允许 app_user 插入 users 表

REVOKE:收回权限
REVOKE 的语法和 GRANT 正好相反,用于收回已经授予的权限。

-- 收回 app_user 对 orders 表的 DELETE 权限
REVOKE DELETE ON TABLE orders FROM app_user;

22.3 角色继承

这是 PostgreSQL 角色系统最优雅的部分。我们可以把权限授予一个“组角色”,然后让其他用户角色“加入”这个组,从而自动继承组的所有权限。

这极大地简化了权限管理。当有新员工入职时,你不需要再为他单独执行一长串 GRANT 命令,只需要把他加入对应的组即可。

场景:我们创建一个 readonly_group 组,这个组对所有核心业务表都有只读权限。然后我们创建一个实习生用户 intern_user,让他加入这个组。

第一步:创建组角色和用户角色

-- 组角色,不允许登录
CREATE ROLE readonly_group;

-- 实习生用户
CREATE USER intern_user WITH LOGIN PASSWORD 'another_password';

第二步:给“组”授权

GRANT USAGE ON SCHEMA public TO readonly_group;
GRANT SELECT ON TABLE users TO readonly_group;
GRANT SELECT ON TABLE orders TO readonly_group;
GRANT SELECT ON TABLE products TO readonly_group; -- 假设还有个 products 表
-- ... 可能还有很多其他表的 SELECT 权限

第三步:让用户“加入”组
使用
GRANT 命令,但这次的对象是角色。

GRANT readonly_group TO intern_user;

现在,intern_user 就自动拥有了 readonly_group 的所有权限!他可以登录,并对 users, orders, products 等表进行只读查询。

管理默认权限 (ALTER DEFAULT PRIVILEGES)
上面的授权方式有一个痛点:当未来我们新建了一张表 new_sales 时,readonly_group 并不会自动拥有对这张新表的 SELECT 权限,我们必须手动再 GRANT 一次。

ALTER DEFAULT PRIVILEGES 命令就是为了解决这个问题。它可以为一个用户(通常是一个“所有者”角色)设定一个“默认权限模板”。当这个用户未来创建新对象时,会自动将这些默认权限授予指定的角色。

-- 假设我们的表都是由 "db_owner" 这个角色创建的
-- 我们现在设置:未来由 db_owner 创建的任何新表,都自动把 SELECT 权限授予 readonly_group
ALTER DEFAULT PRIVILEGES FOR ROLE db_owner IN SCHEMA public
GRANT SELECT ON TABLES TO readonly_group;

-- 现在,如果 db_owner 创建了一张新表
-- CREATE TABLE new_sales (...);
-- 那么 readonly_group 会自动拥有对 new_sales 的 SELECT 权限,无需手动授权!

本章小结

你已经掌握了如何为你的数据库建立一套强大、灵活、易于维护的安保系统。

  • 我们理解了 PostgreSQL 中**用户和组都统一为“角色”**的概念。
  • 学会了使用 CREATE ROLECREATE USER创建角色
  • 掌握了使用 GRANTREVOKE 来精确地授予和收回权限
  • 学习了如何利用角色继承来模拟“用户组”,极大地简化了权限管理。
  • 了解了 ALTER DEFAULT PRIVILEGES 这个高级工具,可以实现对未来新对象的自动授权

遵循最小权限原则,善用角色继承,是保证生产数据库安全的第一道,也是最重要的一道防线。

在下一章,我们将学习如何在 PostgreSQL 中编写自定义函数和存储过程。这将允许我们把复杂的业务逻辑封装在数据库内部,供应用程序调用。准备好在数据库里“写代码”了吗?我们下一章见!

原文链接:,转发请注明来源!