1. PostgreSQL用户管理基础概念
在PostgreSQL数据库系统中,用户管理是数据库安全与权限控制的核心环节。与许多关系型数据库不同,PostgreSQL采用基于角色的访问控制(RBAC)模型,将"用户"和"角色"的概念统一处理。这种设计使得权限管理更加灵活,同时也带来了一些独特的操作方式。
PostgreSQL中的每个用户本质上都是一个可以登录的角色(LOGIN ROLE),这些用户信息存储在系统目录pg_authid中。当我们谈论"查看用户"时,实际上是在查询这些系统目录表和视图。理解这一点非常重要,因为直接查询底层系统表可能会暴露敏感信息,而通过特定的视图查询则更加安全规范。
注意:在生产环境中,查询用户信息需要相应的权限。通常只有超级用户或具有特定权限的角色才能查看完整的用户列表和属性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 查看用户列表的四种标准方法
2.1 使用\du元命令
在psql交互式终端中,最快捷的方法是使用\du(describe users)命令:
sql复制\du
这个命令会返回一个格式化的列表,包含:
- 角色名称
- 角色属性列表(如是否可以登录、是否是超级用户等)
- 所属的角色组
- 描述信息
\du命令实际上是查询pg_roles系统视图的快捷方式,它自动处理了格式化和显示逻辑,非常适合日常管理使用。
2.2 查询pg_user视图
对于需要在应用程序中集成用户查询功能的情况,可以查询pg_user视图:
sql复制SELECT * FROM pg_user;
这个视图提供了以下关键字段:
- usename:用户名
- usesysid:用户在系统中的数字ID
- usecreatedb:用户是否有创建数据库的权限
- usesuper:用户是否为超级用户
- usebypassrls:用户是否绕过行级安全策略
- passwd:密码字段(通常显示为********)
- valuntil:密码过期时间
- useconfig:运行时配置变量
pg_user视图相比直接查询系统表更加安全,因为它隐藏了敏感信息并提供了标准化的接口。
2.3 查询pg_roles系统目录
如果需要更详细的角色信息,可以查询pg_roles系统目录:
sql复制SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb,
rolcanlogin, rolreplication, rolconnlimit, rolpassword, rolvaliduntil
FROM pg_roles;
这个查询返回的信息比pg_user更全面,包括:
- rolcanlogin:标识该角色是否可以登录(即是否是用户)
- rolconnlimit:连接数限制
- rolpassword:密码加密后的哈希值(如果配置了密码)
- rolvaliduntil:密码过期时间戳
2.4 使用information_schema
对于需要跨数据库兼容的应用程序,可以使用SQL标准的information_schema:
sql复制SELECT * FROM information_schema.enabled_roles;
这种方法返回的信息较为基础,但优点是兼容其他支持SQL标准的数据库系统。
3. 高级用户信息查询技巧
3.1 查看用户权限详情
了解用户拥有的具体权限比单纯查看用户列表更为重要。以下查询可以显示用户的详细权限:
sql复制SELECT
r.rolname,
ARRAY(
SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid
) as member_of,
r.rolsuper,
r.rolinherit,
r.rolcreaterole,
r.rolcreatedb,
r.rolcanlogin,
r.rolconnlimit,
r.rolvaliduntil,
r.rolreplication,
r.rolbypassrls
FROM pg_roles r
WHERE r.rolcanlogin
ORDER BY 1;
3.2 查看用户对象权限
要查看特定用户对数据库对象的权限,可以使用以下查询:
sql复制SELECT
grantee,
table_schema,
table_name,
privilege_type
FROM information_schema.table_privileges
WHERE grantee = 'username';
3.3 检查密码加密方式
PostgreSQL支持多种密码加密算法,查看当前配置的方法:
sql复制SHOW password_encryption;
要查看特定用户的密码加密信息:
sql复制SELECT rolname, rolpassword
FROM pg_authid
WHERE rolcanlogin;
4. 用户信息查询的实用脚本
4.1 导出用户列表脚本
以下是一个实用的shell脚本,用于导出PostgreSQL用户列表到CSV文件:
bash复制#!/bin/bash
psql -U postgres -d postgres -c "\copy (SELECT rolname as username, rolcanlogin as can_login, rolcreatedb as can_create_db, rolsuper as is_superuser, rolvaliduntil as password_expires FROM pg_roles WHERE rolname !~ '^pg_' ORDER BY rolname) TO '/tmp/postgres_users.csv' WITH CSV HEADER"
4.2 用户登录监控查询
监控当前登录用户的活动:
sql复制SELECT
usename,
client_addr,
application_name,
backend_start,
state,
query
FROM pg_stat_activity
WHERE usename IS NOT NULL;
4.3 用户密码过期检查
检查即将过期的用户密码:
sql复制SELECT
rolname,
rolvaliduntil
FROM pg_authid
WHERE rolvaliduntil IS NOT NULL
AND rolvaliduntil < CURRENT_TIMESTAMP + INTERVAL '30 days'
ORDER BY rolvaliduntil;
5. 安全最佳实践
5.1 查询权限控制
在生产环境中,应该限制普通用户查询敏感用户信息的权限。可以通过以下方式实现:
- 创建只读角色:
sql复制CREATE ROLE user_viewer;
GRANT pg_read_all_stats TO user_viewer;
- 限制特定视图的访问:
sql复制CREATE VIEW limited_user_view AS
SELECT rolname, rolcanlogin, rolcreatedb
FROM pg_roles
WHERE rolname !~ '^pg_';
GRANT SELECT ON limited_user_view TO user_viewer;
5.2 审计日志配置
启用用户查询的审计日志:
postgresql.conf复制log_statement = 'ddl'
log_connections = on
log_disconnections = on
log_line_prefix = '%m [%p] %q%u@%d '
5.3 敏感信息保护
避免在日志或应用中暴露密码哈希:
sql复制-- 不安全的方式
SELECT * FROM pg_shadow;
-- 安全的方式
SELECT usename, useconfig FROM pg_user;
6. 常见问题排查
6.1 查询返回空列表
如果用户查询返回空列表,可能的原因包括:
-
连接使用的角色没有足够权限
sql复制SELECT current_user;解决方案:使用超级用户账户或请求管理员授予权限
-
查询条件过于严格
sql复制-- 尝试更宽松的查询 SELECT rolname FROM pg_roles;
6.2 密码字段显示为********
这是PostgreSQL的安全特性,要查看密码哈希(需要超级用户权限):
sql复制SELECT rolname, rolpassword FROM pg_authid WHERE rolcanlogin;
6.3 用户存在但无法登录
检查以下常见问题:
-
用户是否被锁定:
sql复制SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname = 'username'; -
密码是否过期:
sql复制SELECT rolname, rolvaliduntil FROM pg_authid WHERE rolname = 'username'; -
pg_hba.conf配置是否允许连接:
bash复制grep 'host' ${PGDATA}/pg_hba.conf
7. 性能优化建议
7.1 大型系统的用户查询优化
对于拥有数千用户的PostgreSQL实例,查询用户信息可能会影响性能。建议:
- 为pg_roles创建索引:
sql复制CREATE INDEX idx_roles_rolname ON pg_roles(rolname);
- 使用物化视图缓存用户信息:
sql复制CREATE MATERIALIZED VIEW mv_user_info AS
SELECT rolname, rolcanlogin, rolcreatedb, rolsuper
FROM pg_roles
WHERE rolcanlogin
WITH DATA;
REFRESH MATERIALIZED VIEW mv_user_info;
- 限制返回的列数,避免查询不需要的信息
7.2 定期清理非活跃用户
识别长期未登录的用户:
sql复制SELECT
r.rolname,
MAX(a.backend_start) AS last_login
FROM pg_roles r
LEFT JOIN pg_stat_activity a ON r.rolname = a.usename
WHERE r.rolcanlogin
GROUP BY r.rolname
ORDER BY last_login;
8. 跨版本兼容性
不同PostgreSQL版本在用户管理方面有所差异:
| 版本 | 重要变化 |
|---|---|
| 9.6- | 使用pg_shadow视图查看用户密码 |
| 10+ | 引入pg_authid系统目录替代部分功能 |
| 14+ | 新增pg_ident_file_mappings视图 |
| 15+ | 移除password_encryption='plain'选项 |
对于需要支持多版本的应用,建议使用information_schema视图或特性检测:
sql复制SELECT current_setting('server_version_num')::int/10000 AS major_version;
9. 与外部工具集成
9.1 使用pgAdmin查看用户
在pgAdmin图形界面中:
- 展开服务器 → 登录/组角色
- 右键点击特定用户查看属性
- 使用"统计"选项卡查看用户活动
9.2 通过Python脚本查询用户
使用psycopg2库的示例:
python复制import psycopg2
conn = psycopg2.connect("dbname=postgres user=admin")
cur = conn.cursor()
cur.execute("""
SELECT rolname, rolcanlogin, rolcreatedb
FROM pg_roles
WHERE rolname !~ '^pg_'
""")
for user in cur.fetchall():
print(f"User: {user[0]}, Can login: {user[1]}, Can create DB: {user[2]}")
conn.close()
9.3 通过REST API暴露用户信息
使用PostgREST的示例配置:
ini复制# postgrest.conf
db-uri = "postgres://authenticator:password@localhost:5432/postgres"
db-schemas = "public"
db-anon-role = "anon"
db-pre-request = "public.check_access"
创建视图和权限:
sql复制CREATE VIEW api.users AS
SELECT rolname as username, rolcreatedb as can_create_db
FROM pg_roles
WHERE rolcanlogin;
GRANT SELECT ON api.users TO anon;
10. 深入理解用户系统表
要真正掌握PostgreSQL用户管理,需要理解几个关键系统表:
- pg_authid:存储认证信息(密码哈希等),只有超级用户可以查询
- pg_roles:包含pg_authid的非敏感信息,可供更多角色访问
- pg_auth_members:记录角色之间的成员关系
- pg_user:面向用户的视图,显示可登录角色的基本信息
查看表关系的查询:
sql复制SELECT
c.relname AS table_name,
a.attname AS column_name,
t.typname AS data_type
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid
JOIN pg_type t ON a.atttypid = t.oid
WHERE c.relname IN ('pg_authid', 'pg_roles', 'pg_auth_members')
AND a.attnum > 0
ORDER BY c.relname, a.attnum;
理解这些底层数据结构有助于在复杂场景下进行故障排除和性能优化。
