---

title: GraphQL字段级审计与策略联动最佳实践

keywords:

  • GraphQL
  • 字段审计
  • Resolver Hook
  • Scope
  • OperationName
  • Persisted Query
  • Metrics
  • Policy
  • 追踪
  • 聚合

description: 构建字段级审计与策略联动方案,记录字段访问与用户上下文,按Scope策略联动拦截并聚合指标(操作名/持久化查询),附Resolver钩子与守卫示例。

categories:

  • 文章资讯
  • 技术教程

---

一、策略与上下文

type Token = { sub: string; scope: string[] }
const fieldScope: Record<string, string> = { email: 'read:email', ssn: 'read:ssn', balance: 'read:balance' }
function hasScope(tok: Token, need: string): boolean { return tok.scope.includes(need) }

二、审计钩子

type Audit = { id: string; userId: string; field: string; operation: string; persistedId?: string; timestamp: string }
function nowIso(): string { return new Date().toISOString() }

function auditField(userId: string, field: string, operation: string, persistedId?: string): Audit {
  return { id: String(Date.now()) + Math.random().toString(36).slice(2), userId, field, operation, persistedId, timestamp: nowIso() }
}

三、守卫与联动

function guardField(tok: Token, fields: string[]): boolean {
  for (const f of fields) { const need = fieldScope[f]; if (need && !hasScope(tok, need)) return false }
  return true
}

四、聚合指标

class Metrics {
  counts = new Map<string, number>()
  inc(key: string) { const n = (this.counts.get(key) || 0) + 1; this.counts.set(key, n) }
  get(key: string): number { return this.counts.get(key) || 0 }
}

function keyOf(operation: string, field: string): string { return `${operation}:${field}` }

五、整合示例

type Req = { body: { query: string; operationName?: string; persistedId?: string }; token: Token }
type Res = { status: (n: number) => Res; end: (b?: string) => void }

function extractFields(query: string, allow: string[]): string[] { const out: string[] = []; for (const f of allow) { const re = new RegExp(`\\b${f}\\b`); if (re.test(query)) out.push(f) } return out }

function resolverGuard(req: Req, res: Res, metrics: Metrics): boolean {
  const op = req.body.operationName || 'unknown'
  const id = req.body.persistedId
  const fields = extractFields(req.body.query, Object.keys(fieldScope))
  if (!guardField(req.token, fields)) { return res.status(403).end('forbidden'), false }
  for (const f of fields) metrics.inc(keyOf(op, f))
  return true
}

function resolverAudit(req: Req): Audit[] {
  const op = req.body.operationName || 'unknown'
  const id = req.body.persistedId
  const fields = extractFields(req.body.query, Object.keys(fieldScope))
  return fields.map(f => auditField(req.token.sub, f, op, id))
}

六、验收清单

  • 字段级Scope策略联动拦截;未授权字段拒绝且记录审计。
  • 指标按operation:field聚合;持久化查询ID参与审计与追踪。
  • Resolver钩子输出包含用户与字段、操作名与时间戳;与守卫协同生效。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部