后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载本指南以 PostGraphile v5Graphile Crystal 单仓中的安全设计为主线讲解如何把身份认证与授权逻辑下沉到 PostgreSQL 数据库层先理解行级安全Row-Level Security, RLS为何成为现代应用的默认安全边界再掌握通过pgSettings将框架层认证结果Session、JWT、API Key 等注入数据库会话、用current_setting在 RLS 策略中消费身份数据以及直接从 PostgreSQL 函数签发 JWT 的完整方案。读完本文你将能够在自己的graphile.config.*与数据库 schema 中落地一套「数据库层单一授权点」的安全架构。为什么要把安全下沉到数据库层传统的 Web 应用架构中安全逻辑通常全部实现在服务器层数据库被当作单纯的数据存储。这种分工部分源于历史限制——PostgreSQL 等数据库提供的权限策略粒度不够细部分则出于「减少数据库负载、提升可扩展性」的考量。但随着应用增长多服务直接访问数据库的需求越来越常见这种架构暴露出两个痛点逻辑重复在多个位置复制认证/授权逻辑容易产生不一致并扩大潜在的攻击面单点瓶颈强制所有访问都经过原应用层应用层会成为开发与性能的双重瓶颈。PostgreSQL 9.52016 年初引入的行级安全RLS策略改变了这一局面。RLS 与 PostgreSQL 基于角色的成熟权限体系表级、列级权限叠加可以做到非常精细的权限控制在既有表级、列级权限之上再增加行级约束。PostGraphile 官方建议保护你架构的最底层——数据本身。这样无论有多少个微服务与数据库交互它们都受同一套只维护一次的基础权限逻辑保护新增微服务可以直接对话数据库而无需复制认证逻辑。注意当 RLS 启用时默认情况下所有行对任何角色都不可见数据库管理角色与建表角色除外权限通过策略policy选择性授予。PostGraphile 的安全模型API 是薄层数据库是安全边界如果你的数据库 schema 已经用 RLS、触发器函数等技术在最低层保护好了数据那么postgraphile可以非常快速地基于它生成一个强大、安全、高性能的 GraphQL API。PostGraphile 只需要足够的上下文——即通过pgSettings了解「当前请求是谁发起的」其余安全判定全部交由数据库完成。从源码看pgSettings是每个pgService数据库服务配置的核心属性之一其类型为Recordstring, string | undefined | null由服务端按请求回调计算随后在事务内应用到数据库会话grafast/dataplan-pg/src/adaptors/pg.ts。也就是说PostGraphile 自身不复制授权逻辑它只是把身份信息「搬运」给 PostgreSQL让 RLS 策略成为唯一授权裁决者。认证策略Session、JWT 与其他令牌PostGraphile 不推荐某一种认证方式优于另一种选择取决于你的基础设施与长期维护计划。官方认可的策略包括Session会话使用框架自带的 session 中间件如express-session、fastify/session。会话校验通过后把用户标识与相关标志位复制进pgSettings。JWT在任意中间件中校验令牌然后把所需 claims 映射进 PostgreSQL。完整流程参见 JWT 指南其遵循的序列化规则见 PostgreSQL JWT 规范。其他令牌API keys、mTLS 属性、OAuth access token 或其他凭据均可认证调用者同样只需把你需要的身份/策略数据转换成pgSettings的值。警告lazy-jwt只是过渡方案postgraphile/presets/lazy-jwt预设可以解码简单的 Bearer 令牌但它刻意不处理刷新令牌refresh tokens、令牌吊销revocation与自定义 claim 映射。它适合帮助你快速起步但不要作为长期方案。从源码看该预设由PgJWTPlugin与GrafservPgJWTPlugin两个插件组成postgraphile/postgraphile/src/presets/lazy-jwt.ts它只在 grafserv HTTP 适配器下运行从requestContext.node?.req?.headers?.authorization读取 Bearer 令牌用共享密钥preset.grafserv.pgJwtSecret或preset.schema.pgJwtSecret以HS256/HS384算法、默认 audiencepostgraphile校验随后把roleclaim 与合法的字母数字 claim 写入pgSettings的jwt.claims.*命名空间。生产环境的刷新令牌、密钥轮换、吊销列表、多租户密钥查找等需求它都无法满足。把身份信息注入 PostgreSQLgrafast.context pgSettings你的认证层运行在 Web 框架内PostgreSQL 只看到你放入pgSettings的值。最常见的方式是在preset.grafast.context回调中从框架的 request 对象拷贝数据export default { grafast: { async context(requestContext, args) { const req requestContext.expressv4?.req; const pgSettings { ...args.contextValue?.pgSettings, } as Recordstring, string; if (req?.user?.id) { pgSettings[myapp.user_id] String(req.user.id); } if (req?.user?.is_admin) { pgSettings[myapp.is_admin] true; } return { ...args.contextValue, pgSettings, }; }, }, };关键点务必先展开args.contextValue?.pgSettings把 pgService 适配器及预设如lazy-jwt已添加的设置保留下来再叠加自己的值pgSettings的值最终会被String()转为字符串set_config只接受字符串所以布尔值、数字要显式转换如true命名规范自定义变量必须包含一到两个英文句点且句点前的前缀不能被任何 PostgreSQL 扩展占用推荐使用jwt.或myapp.这类前缀不含句点的键会被解释为 PostgreSQL 内部设置如role并直接生效。详见 配置文档 pgSettings 一节。在 PostgreSQL 中用current_setting读取这些值create function myapp.current_user_id() returns uuid as $$ select nullif(current_setting(myapp.user_id, true), )::uuid; $$ language sql stable;然后把该函数或直接调用current_setting放进 Row Level Security 策略中执行你的规则。关于「如何暴露 HTTP 头或其他请求元数据」的更多变体参考配置文档。pgSettings 的底层实现事务内的 set_config从dataplan/pg适配器源码可以看到grafast/dataplan-pg/src/adaptors/pg.ts为减少往返适配器把全部设置打包为一次查询执行select set_config(el-0, el-1, true) from json_array_elements($1::json) el;其中$1是[[key,value], ...]形式的 JSON 数组。第三个参数true表示set_config只在当前事务内生效事务结束COMMIT/ROLLBACK后自动重置。为便于理解等效的逐条写法如下begin; set local myapp.user_id to 2; -- 在此执行 GraphQL 查询 commit;事务结束后myapp.user_id即被清除避免设置泄漏到连接池中的其他请求。在 RLS 策略中使用这些值current_setting(name, true)的第二个参数表示「该属性允许缺失」。封装一个辅助函数可以让策略保持整洁create function current_user_id() returns integer as $$ select nullif(current_setting(myapp.user_id, true), )::integer; $$ language sql stable;然后在策略中直接依赖它create policy update_if_author on comments for update using (userId current_user_id()) with check (userId current_user_id());从 PostgreSQL 签发 JWTPostGraphile 还支持在 PostgreSQL schema 内部轻松生成 JWT。做法是先在preset.gather.pgJwtTypes中指定一个复合类型export default { gather: { pgJwtTypes: jwt_token, }, //... };该配置项的值是一个「schema 名 类型名」的元组类型为元组所指类型的值从 PostgreSQL 函数返回时PostGraphile 会用你的 JWT 密钥对它签名并以字符串 JWT 形式放进 GraphQL 响应载荷。例如在 PostgreSQL 中定义复合类型create type my_public_schema.jwt_token as ( role text, exp integer, person_id integer, is_admin boolean, username varchar );然后使用如下配置运行 PostGraphileimport { PostGraphileAmberPreset } from postgraphile/presets/amber; export default { extends: [PostGraphileAmberPreset], gather: { // highlight-next-line pgJwtTypes: my_public_schema.jwt_token, }, schema: { // highlight-next-line pgJwtSecret: process.env.JWT_SECRET, }, };最后添加一个 PostgreSQL 认证函数例如create function my_public_schema.authenticate( email text, password text ) returns my_public_schema.jwt_token as $$ declare account my_private_schema.person_account; begin select a.* into account from my_private_schema.person_account as a where a.email authenticate.email; if account.password_hash crypt(password, account.password_hash) then return ( person_role, extract(epoch from now() interval 7 days), account.person_id, account.is_admin, account.username )::my_public_schema.jwt_token; else return null; end if; end; $$ language plpgsql strict security definer;这将生成一个authenticatemutation你可以在响应载荷中提取jwtToken。要点与边界pgJwtTypes支持字符串或字符串数组等同于给这些类型附加-table jwt行为签名使用preset.schema.pgJwtSecret与可选的preset.schema.pgJwtSignOptions该功能只管签名你返回的复合类型载荷不管理刷新令牌也不构成完整的认证系统生成的令牌由你自己编写的中间件或仍在使用中的lazy-jwt预设校验。请对照 PostgreSQL JWT 规范 检查返回的字段能否干净地映射到 PostgreSQL 会话设置从 v4 迁移的用户会看到对应关系v4 兼容预设把jwtPgTypeIdentifier映射为pgJwtTypes、把jwtSecret映射为pgJwtSecretpostgraphile/postgraphile/src/presets/v4.ts旧项目可按此迁移。在 PostgreSQL 中使用这些值JWT claim 的序列化规则无论你用 Session、JWT 还是其他机制认证PostGraphile 最终都会把你放进pgSettings的数据设置为 PostgreSQL 参数。JWT 场景下PostgreSQL JWT 规范 精确规定了 claim 的映射方式其核心原则同样适用于你自定义的任何前缀roleclaim 通过set local role $role;切换数据库角色其余所有 claim含iss、sub等注册 claim以及role本身通过set local jwt.claims.$claim_name to $claim_value;写入jwt.claims命名空间。例如一个包含以下 claims 的 JWT{ sub: postgraphql, role: user, user_id: 2 }会转化为如下 SQLset local role user; set local jwt.claims.sub to postgraphql; set local jwt.claims.role to user; set local jwt.claims.user_id to 2;规范建议始终使用SET ... LOCAL或等价的set_config(..., true)确保每个事务块BEGIN…COMMIT/ROLLBACK拥有自己独立的参数作用域事务提交后参数即失效避免跨请求泄漏。在 PostgreSQL 中可通过select current_setting(jwt.claims.user_id);或show jwt.claims.user_id;检索这些值。实战检查清单围绕本指南落地一套安全的 PostGraphile 应用时建议核对数据库先行在 PostgreSQL 中启用 RLS为所有表创建基于角色的策略并用current_setting读取身份数据框架层只做认证Session/JWT/mTLS/API Key 的校验放在 Web 框架中间件中PostGraphile 侧不复制逻辑最小化传参只把 RLS 策略真正需要的 claim 传入pgSettings不要盲目透传整个 JWT 载荷遵守命名规范自定义设置使用myapp.或jwt.前缀防止与 PostgreSQL 内部设置或扩展冲突警惕lazy-jwt仅用于快速起步尽早替换为显式设置pgSettings的中间件以支持刷新、吊销、密钥轮换等生产需求事务隔离理解set_config(..., true)/SET LOCAL的事务级作用域防止连接池复用带来的数据串号。赞分享后端API网关【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址https://gitcode.com/gh_mirrors/cry/crystal点击查看免费下载相关推荐PostGraphile v5 安全架构实战用 pgSettings Row Level Security 把授权下沉到 PostgreSQLPostGraphile v5 安全架构实战用 pgSettings Row Level Security 把授权下沉到 PostgreSQL PostG后端API网关PostGraphile 安全实战用 PostgreSQL RLS 与 JWT 构建端到端认证授权体系PostGraphile 安全实战用 PostgreSQL RLS 与 JWT 构建端到端认证授权体系 本篇技术指南以 PostGraphile v4 官方安后端API网关认证与授权完全指南从 Session、JWT 到 OAuth 2.0 的后端身份安全实战认证与授权完全指南从 Session、JWT 到 OAuth 2.0 的后端身份安全实战 导读 认证Authentication与授权Authoriz教程文档人工智能Vibe Coding上一篇Office RibbonX Editor零编程定制Office功能区的终极免费指南下一篇网盘下载限速终结者九大平台直链解析全攻略创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考