ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SparkyFitness 外部 PostgreSQL 接入完整指南:双角色权限模型、RLS 与安全加固实战

SparkyFitness 外部 PostgreSQL 接入完整指南:双角色权限模型、RLS 与安全加固实战 后端前端移动开发【免费下载链接】SparkyFitnessSparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.项目地址https://gitcode.com/gh_mirrors/sp/SparkyFitness点击查看免费下载本文是 SparkyFitness 服务端对接自有 PostgreSQL 实例AWS RDS、Azure Database、CloudNativePG 或本地自装的实操指南涵盖双数据库角色DB User / App User的两种初始化方案、PgBouncer 会话池约束、Unix Socket 直连、以及首次启动后的CREATEROLE撤销加固。读完本文你将能够独立完成外部数据库的建库、授权、环境变量配置与启动验证并理解迁移器、权限授予脚本和 RLS 策略在底层是如何协同工作的。[!WARNING]社区支持声明外部与托管数据库配置未经核心维护者官方测试与支持请自行评估风险后使用本指南。1. 数据库与用户双角色模型SparkyFitness 使用两个独立的 PostgreSQL 角色角色环境变量用途DB Owner 用户SPARKY_FITNESS_DB_USER执行迁移创建 schema、表、函数、索引与 schema 管理App 用户SPARKY_FITNESS_APP_DB_USER应用组件日常读写权限受限这一设计在服务端源码中体现得非常明确连接池管理器 在模块加载时同时创建两个连接池Owner 池使用SPARKY_FITNESS_DB_USER/SPARKY_FITNESS_DB_PASSWORD供迁移器与系统级操作使用见getSystemClientApp 池使用SPARKY_FITNESS_APP_DB_USER/SPARKY_FITNESS_APP_DB_PASSWORD供业务查询使用见getClient且每个业务连接都会先执行SELECT public.set_app_context($1, $2)以设置 RLS 上下文。两个池默认max: 10、idleTimeoutMillis: 30000、connectionTimeoutMillis: 5000端口缺省5432源码第 28/45 行。[!IMPORTANT] 应用会在首次启动时自动创建 App 用户SPARKY_FITNESS_APP_DB_USER并授予全部必要权限因此DB 用户Owner必须拥有CREATEROLE权限。Option A —— 标准方案应用自动创建 App 用户以数据库超级用户身份执行-- 1. 创建数据库 CREATE DATABASE sparkyfitness_db; -- 2. 创建 DB Owner 用户对应 .env 中的 SPARKY_FITNESS_DB_USER CREATE USER sparky_admin WITH PASSWORD your_secure_password; -- 3. 授予数据库所有权使 sparky_admin 可以创建 schema 与表 ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin; -- 4. 授予角色创建权限 -- 应用首次启动时据此自动创建 SPARKY_FITNESS_APP_DB_USER --对应后端实现 SparkyFitnessServer/utils/dbMigrations.ts ALTER USER sparky_admin CREATEROLE; -- 5. 仅 PostgreSQL 15 需要PG 15 起 public schema 默认权限发生变化 -- 需显式授予 owner 创建权限 GRANT ALL ON SCHEMA public TO sparky_admin;启动时应用会检查角色是否已存在SELECT 1 FROM pg_roles WHERE rolname $1不存在则执行CREATE ROLE并在创建成功后输出日志Successfully created role: app user见 迁移器源码。Option B —— 最小权限方案手动预创建 App 用户如果托管环境不允许CREATEROLE如严格管控的托管数据库可以手动预创建 App 用户。应用启动时会先检测角色是否已存在——若角色已存在则完全跳过CREATE ROLE此时不需要CREATEROLE。-- 1. 创建数据库 CREATE DATABASE sparkyfitness_db; -- 2. 创建 DB Owner 用户对应 .env 中的 SPARKY_FITNESS_DB_USER CREATE USER sparky_admin WITH PASSWORD your_secure_password; -- 3. 授予数据库所有权 ALTER DATABASE sparkyfitness_db OWNER TO sparky_admin; -- 4. 仅 PostgreSQL 15 需要 GRANT ALL ON SCHEMA public TO sparky_admin; -- 5. 预创建 App 用户对应 .env 中的 SPARKY_FITNESS_APP_DB_USER -- 应用检测到该角色已存在即跳过 CREATE ROLE -- 因此 sparky_admin 不需要 CREATEROLE。 CREATE USER sparky_app WITH PASSWORD another_secure_password;然后在.env中设置两个用户SPARKY_FITNESS_DB_USERsparky_admin SPARKY_FITNESS_DB_PASSWORDyour_secure_password SPARKY_FITNESS_APP_DB_USERsparky_app SPARKY_FITNESS_APP_DB_PASSWORDanother_secure_password[!NOTE] Option B 下sparky_admin仍需数据库所有权来运行迁移建表、schema、函数、索引唯一不再需要的权限是CREATEROLE。密码校验与同步机制源码级解读迁移器对已存在角色的处理并非简单跳过而是先做认证探测appRoleCanAuthenticate见 dbMigrations.ts用SPARKY_FITNESS_APP_DB_USERSPARKY_FITNESS_APP_DB_PASSWORD新建一次性客户端尝试连接仅当返回 SQLSTATE28P01密码错误或28000认证失败时判定密码失配其余错误主机不可达、库不存在等直接抛出避免误判密码匹配 → 输出Role app user already exists.不执行任何ALTER ROLEOwner 无需CREATEROLE密码失配 → 执行ALTER ROLE ... WITH LOGIN PASSWORD ...若因缺少CREATEROLE报42501会抛出带明确指引的错误要么把.env中的密码改回该角色实际使用的密码要么以超级用户手动执行ALTER ROLE app user WITH PASSWORD new password;。2. 环境变量完整配置在.env中指向你的外部数据库SPARKY_FITNESS_DB_HOSTyour-db-host SPARKY_FITNESS_DB_NAMEsparkyfitness_db SPARKY_FITNESS_DB_USERsparky_admin SPARKY_FITNESS_DB_PASSWORDyour_secure_password SPARKY_FITNESS_DB_PORT5432 # App 用户 —— Option A 自动创建或 Option B 由你预创建 SPARKY_FITNESS_APP_DB_USERsparky_app SPARKY_FITNESS_APP_DB_PASSWORDanother_secure_password两个 App 变量必须显式设置SPARKY_FITNESS_APP_DB_USER与SPARKY_FITNESS_APP_DB_PASSWORD在标准 Docker Compose 安装下是可选的——服务端会默认取sparky_app并每次启动临时生成密码。但外部数据库必须两者都显式设置因为角色的生命周期由你掌控Option A应用使用这两个值自动创建该角色Option B角色已存在.env中的密码必须与创建时设置的一致。服务端启动时会以该角色身份连接验证校验通过则不会发出ALTER ROLEOwner 依然不需要CREATEROLE。如果.env中的密码与角色实际密码失配服务端会更新角色以匹配——这需要CREATEROLE。在刻意收回该权限的数据库上请自行保持两者同步否则服务端会报错并提示你执行哪条ALTER ROLE。这一默认行为在 预检脚本 中实现未设置SPARKY_FITNESS_APP_DB_USER时默认sparky_app未设置SPARKY_FITNESS_APP_DB_PASSWORD时用crypto.randomBytes(32)生成临时密码——并明确提示若多个服务端共享同一数据库必须显式设置。PgBouncer必须使用 Session 模式若通过 PgBouncer 连接必须使用 session pooling。事务池transaction pooling与语句池statement pooling均与 SparkyFitness 基于会话的用户权限和启动迁移锁不兼容——应用连接与迁移连接都必须保留各自的 PostgreSQL 会话。断连恢复与 TCP Keepalive如果某个服务端节点在数据库初始化期间故障且未关闭连接其他实例会一直等待直到 PostgreSQL 检测到连接丢失并释放启动锁。Linux 默认 TCP keepalive 设置下空闲连接约需两小时才能被检测到。可按恢复需求调整 PostgreSQL 的 TCP keepalive 配置tcp_keepalives_idle等client_connection_check_interval能让运行中的查询及时感知已检测到的断连idle_session_timeout可终止事务外空闲的遗弃会话但不覆盖运行中的查询或空闲事务且对连接池场景需谨慎使用。若使用代理还需配置代理对客户端失连的检测。通过 Unix Socket 连接若 PostgreSQL 与后端同宿主机可通过 Unix 域套接字代替 TCP 连接。把SPARKY_FITNESS_DB_HOST设为套接字目录任何以/开头的值都被视为套接字路径而非主机名SPARKY_FITNESS_DB_HOST/var/run/postgresql SPARKY_FITNESS_DB_PORT5432驱动会在该目录后追加.s.PGSQL.port因此SPARKY_FITNESS_DB_PORT仍然重要——它决定套接字文件名而非 TCP 端口。这一机制同时适用于应用连接池与内置备份/恢复后者会以子进程方式调用pg_dump、psql、dropdb、createdb见 备份服务实现。[!IMPORTANT]SPARKY_FITNESS_DB_PASSWORD与SPARKY_FITNESS_APP_DB_PASSWORD始终为必填——即使pg_hba.conf的 local 行使用peer或trust认证、实际不发送密码服务端也会拒绝启动。请设置占位值或改用scram-sha-256并设置真实密码。[!NOTE]Docker 场景容器内无法使用peer认证容器 UID 不会匹配数据库角色。请在pg_hba.conf的 local 行使用scram-sha-256并把套接字目录绑定挂载进容器例如- /var/run/postgresql:/var/run/postgresql。3. PostgreSQL 扩展零依赖[!NOTE]不需要任何扩展。自 v0.17.0 起SparkyFitness 已不再依赖uuid-ossp、pgcrypto与pg_stat_statementsUUID 生成改用内置的gen_random_uuid()PostgreSQL 13无需任何扩展加密完全在应用代码层完成Node.jscrypto的 AES-256-GCM不使用数据库函数。这一点由迁移脚本 20260618000000_remove_superuser_extensions.sql 完整承载且该脚本对托管数据库非常友好Step 1把仍使用uuid_generate_v4()作为默认值的 8 张表如food_entry_meals、sleep_entries、exercise_preset_entries等的列默认值改为gen_random_uuid()全程IF EXISTS幂等守卫Step 2若pgcrypto已安装先把gen_random_uuid()默认值重新绑定到pg_catalog内置函数避免删除 pgcrypto 后旧 PG 安装的 OID 悬空导致插入失败Step 3尝试DROP EXTENSION三个旧扩展并用EXCEPTION WHEN insufficient_privilege / dependent_objects_still_exist / OTHERS优雅跳过——非超级用户环境会自动跳过DROP EXTENSION扩展即使残留也无害。如果你是从旧版本升级且已安装这些扩展该迁移会自动尝试移除无法移除时跳过不影响运行。4. Row Level SecurityRLS与表所有权sparky_admin必须是表的所有者才能启用并管理 RLS 策略。ALTER DATABASE ... OWNER TO sparky_admin确保迁移期间创建的所有表自动归属于sparky_admin。RLS 策略的单一事实来源是 rls_policies.sql它在每次服务端启动、迁移完成后执行以保证安全状态一致先清理publicschema 的全部既有策略再对exercise_entries、food_entries、check_in_photos、family_access等业务表统一ENABLE ROW LEVEL SECURITY并重建策略。而业务连接在 poolManager.ts 的getClient中通过SELECT public.set_app_context($1, $2)注入当前用户上下文由 RLS 完成行级隔离。这也解释了为什么 App 用户只拥有受限权限、而 Owner 必须拥有表——RLS 策略的管理创建、ALTER天然要求表所有者权限。权限授予的完整清单见 grantPermissions.ts迁移完成后会对public、auth、system三个 schema 的现有对象及默认权限授予USAGE、增删改查、序列使用与函数执行权限并单独授予system.schema_migrations的SELECT供应用检查已应用迁移。5. 安全加固仅适用于 Option ACREATEROLE仅在初始安装或未来更新需要创建新的专用角色时才必要。撤销 CREATEROLE应用首次启动成功后看到日志Successfully created role即可撤销该权限ALTER USER sparky_admin NOCREATEROLE;[!CAUTION]撤销后的潜在问题若未来应用更新需要创建新的数据库角色撤销后升级会失败。若后续升级时遇到 Permission Denied 错误请临时重新授予CREATEROLE或以超级用户手动创建所需角色然后再撤销。6. 启动验证与常见问题排查完成上述配置后可按以下顺序验证预检服务端启动先执行runPreflightCheckspreflightChecks.ts。它会补齐缺失的连接默认值SPARKY_FITNESS_DB_HOST默认sparkyfitness-db、SPARKY_FITNESS_DB_NAME默认sparkyfitness_db、SPARKY_FITNESS_DB_USER默认sparky并强制校验SPARKY_FITNESS_DB_PASSWORD、SPARKY_FITNESS_FRONTEND_URL、SPARKY_FITNESS_API_ENCRYPTION_KEY、BETTER_AUTH_SECRET四项必填变量——缺失即 FATAL 拒绝启动角色日志观察启动日志中的Creating role/Role already exists/Successfully updated password分支确认走了预期的 Option A 或 Option B 路径权限日志确认输出Permissions granted to application user.说明grantPermissions已按清单完成授权备份验证外部数据库同样支持内置备份/恢复pg_dump/psql/dropdb/createdb子进程若走 Unix Socket 路径请确认SPARKY_FITNESS_DB_HOST指向的目录可被运行备份的进程访问。典型报错对照现象原因与处理FATAL: Missing required environment variables!四项必填变量缺失按预检输出逐项补齐Cannot update the password for role ... lacks CREATEROLESQLSTATE 42501.env密码与角色实际密码失配且无CREATEROLE改回原密码或超级用户手动ALTER ROLEPgBouncer 下查询异常/迁移锁等待确认使用 session pooling迁移与应用连接需保留完整会话启动长时间卡在迁移锁前序节点异常退出未释放连接等待 keepalive 超时默认约 2 小时可调小tcp_keepalives_idle容器内 Unix Socket 认证失败容器内无法peer认证改用scram-sha-256并绑定挂载套接字目录本文档对应仓库中的原始指南位于 docs/src/install/external-database.md配套后端实现可参阅 SparkyFitnessServer/utils/dbMigrations.ts、SparkyFitnessServer/db/poolManager.ts 与 SparkyFitnessServer/db/grantPermissions.ts迁移脚本位于 SparkyFitnessServer/db/migrations。关于 Docker Compose 自带的数据库编排方式可对照 docker/docker-compose.dev.yml 与 docker/docker-compose.prod.yml 理解两套方案的差异。赞分享后端前端移动开发【免费下载链接】SparkyFitnessSparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.项目地址https://gitcode.com/gh_mirrors/sp/SparkyFitness点击查看免费下载相关推荐终极指南如何使用colorpicker-compose从图片中精准提取颜色终极指南如何使用colorpicker compose从图片中精准提取颜色 colorpicker compose是一个功能强大的Kotlin MultiplRedwoodJS 接入 Netlify Identity 认证从 CLI 安装到 RBAC 角色权限的完整实战指南RedwoodJS 接入 Netlify Identity 认证从 CLI 安装到 RBAC 角色权限的完整实战指南 本篇指南聚焦 RedwoodJS 官方认后端前端Web框架开发工具QuantDinger 多用户部署完全指南PostgreSQL 用户体系、角色权限与生产安全配置QuantDinger 多用户部署完全指南PostgreSQL 用户体系、角色权限与生产安全配置 本文是 QuantDinger v5 多用户运行模式的实操部后端金融科技人工智能AI 应用AI AgentMCP 服务上一篇一次排上千个候选CLM-v0.1-8B免费重排序reranker实战——Best-of-N方案、工具名与下一步动作排序下一篇DeepMind Lab DMLab-30 环境基准全解析30 个程序化任务的环境设计、观测规格与源码实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进