Files
ai-customer-service/prd/IDENTITY_AND_PERMISSION_STRATEGY.md
Your Name 087de4e102 fix(audit): use uuid.New() for ticket workflow audit IDs
Fixes 'invalid input syntax for type uuid' error when writing ticket
workflow audit logs. The audit Event.ID field was using fmt.Sprintf
with nanoseconds ('wf-%d') which doesn't match PostgreSQL's uuid type.

Also adds uuid import to ticket_workflow.go.

Verified: full chain webhook→assign→resolve→close produces 3 audit
logs correctly, no more 'invalid uuid' errors in logs.
2026-05-04 13:44:39 +08:00

5.7 KiB
Raw Permalink Blame History

身份核验与数据权限策略

版本v1.0 | 状态:已生效 关联tech/INTERFACE.md、PRODUCTION_PHASE1_STATUS.md


1. 身份核验

1.1 核验场景

客服系统需要处理两类身份核验:

场景 说明
用户身份核验 验证用户提供的邮箱/手机与注册信息匹配(用于敏感操作如退款查询)
客服身份核验 验证运营后台操作者的身份(防止越权操作)

1.2 用户身份核验

接口tech/INTERFACE.md 定义):

接口 路径 说明
身份校验 GET /internal/supply/users/verify?email={email} 校验用户身份是否匹配
配额查询 GET /internal/runtime/quota?user_id={uid} 查询用户配额
Token 消耗查询 GET /internal/runtime/token-usage?user_id={uid}&window=1d 查询 Token 消耗
错误日志 GET /internal/runtime/error-logs?user_id={uid}&limit=5 查询错误日志

当前状态:上述接口已定义但外部依赖supply-api / token-runtime尚未联调,实际调用可能失败。

核验流程

  1. 用户发起敏感操作(如查询退款状态)
  2. 系统要求用户输入邮箱 + 验证码
  3. 调用 supply-api 校验邮箱是否匹配用户 ID
  4. 匹配成功后执行操作,否则拒绝

1.3 身份核验失败处理

失败次数 处理方式
1-2 次 返回 CS_IDT_4002(验证码错误),允许重试
3 次 返回 CS_SES_4003(身份校验已锁定),锁定 15 分钟
锁定期间 所有身份核验请求返回 403持续 15min 后自动解锁

:失败计数和锁定机制当前未落地P0 缺口),身份校验只返回匹配结果,不做计数锁定。


2. 数据权限策略

2.1 权限基本原则

  • 用户只能查询自己的会话、工单、Token 消耗数据
  • 客服只能操作被分配的工单
  • 管理员可以查看所有数据,但不得泄露给未授权第三方
  • 审计日志不可篡改,所有敏感操作均需记录

2.2 客服操作权限

操作 agent supervisor admin
查看自己被分配的工单
查看所有工单
assign 工单 仅自己的
resolve 工单 仅自己的
查看转人工统计
查看运营大盘
敏感操作(退款)

Phase 1 已落地最小 header-based 鉴权与角色校验(X-CS-Actor-ID / X-CS-Actor-Role),用于保护 ticket/session 后台接口;完整 RBAC、用户级数据隔离与统一身份体系仍未落地仍需在后续阶段补齐。

2.3 跨用户数据隔离

当前状态tech/INTERFACE.md 中各接口的 user_id 隔离依赖调用方传入正确的 user_id,后端不做强制校验。

缺失项P0

  • 所有查询类接口sessions、tickets、quota 等)应强制要求带上 user_id,后端校验 user_id 归属,不允许跨用户查询
  • 客服操作工单时,后端应校验工单的 user_id 与当前操作者的权限范围

建议方案(待 TechLead 评审):

// 中间件层增强
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        claims := getJWTClaims(r)
        ctx := context.WithValue(r.Context(), "user_id", claims.UserID)
        ctx = context.WithValue(ctx, "role", claims.Role)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// 处理器层校验
func (h *TicketHandler) GetTicket(w http.ResponseWriter, r *http.Request) {
    userID := r.Context().Value("user_id")
    ticketID := mux.Vars(r)["id"]
    ticket := h.store.GetTicket(ticketID)
    
    role := r.Context().Value("role")
    if role != "admin" && role != "supervisor" && ticket.UserID != userID {
        writeError(w, "CS_AUTH_4001", 403) // 越权访问
        return
    }
}

3. Webhook 身份校验

3.1 已落地

  • HMAC 签名校验webhook_security.go):验证请求来自合法渠道
  • 时间戳防重放webhook_security.go):防止 replay attack
  • 幂等去重dedup_store.go):防止重复消息

3.2 待补充

项目 优先级 说明
webhook 速率限制 P1 防止恶意刷请求
渠道级独立 webhook 路由 P0 INTERFACE 定义 /webhook/{channel},当前统一入口

4. 敏感数据处理

4.1 敏感字段

字段 处理方式
用户邮箱 脱敏展示(后三位 + @ 前的后三位),如 t***@gmail.com
用户手机 脱敏展示(后四位),如 ***-****-1234
API Key 仅返回前缀后四字符,如 sk-****-abcd
退款金额 日志脱敏,接口明文返回(须登录态)

4.2 当前状态

敏感数据脱敏当前未落地,所有字段明文返回。


5. 审计日志与权限审计

5.1 已落地

  • 审计日志持久化audit_store.go):写入 PostgreSQL cs_audit_logs
  • fail-closed:审计写入失败时整体请求返回错误
  • source_ip / actor_id记录操作来源actor_id 当前有默认值 fallback

5.2 待补充

项目 优先级 说明
安全拒绝事件审计 P0 签名失败、时间戳失败不记审计
工单状态流转审计 P0 assign/resolve 未写审计
source_ip 字段缺失 P0 audit_store 当前未写 source_ip

6. 当前版本状态

  • 本文档版本v1.0
  • 生效日期2026-04-30
  • 下次审查RBAC 权限模型落地后