template-monorepo/docs/identity-member-design.md

12 KiB
Raw Blame History

Identity / Member / Permission 跨模組架構

Gateway 三個業務模組(auth / member / permission)與外部 ZITADEL(身份)、LDAP(企業目錄)、SCIM 2.0(企業 provisioning的整合總覽。內容只談跨模組層次的設計決策與關聯;模組內部請看:

模組 文件
auth internal/model/auth/README.md
member internal/model/member/README.md
permission internal/model/permission/README.md
notification internal/model/notification/README.md

分層公約:docs/model.md


1. 設計目標

目標 說明
統一身份 ZITADEL 為 IdPOIDC、LDAP IdP、Social Login
業務會員 Gateway member 管 tenant-scoped profile
細粒度授權 Gateway permissionCasbin RBAC + Permission TreeB2B 租戶可自定義 Role 並勾選 Permission
對外 Token Gateway 自簽 CloudEP JWTZITADEL OIDC token 只在 /auth/token/exchange 用一次
規模 全平台 100 萬+ 會員;單租戶可達 50 萬
UID 人類可讀帶租戶前綴(如 ACME-10000003);唯一鍵 (tenant_id, uid)

2. 核心原則

  1. 職責分離

    • auth你是誰Authentication
    • member你的業務資料Profile
    • permission你能做什麼Authorization
  2. LDAP 不做登入 bind 登入驗證一律走 ZITADEL LDAP IdPGateway LDAP client 只做 Directory Syncread-only

  3. 租戶隔離 所有持久化資料以 tenant_id 為邊界JWT tenant_id 與請求資源不一致 → 403。

  4. B2B 權限自定義

    • 平台 seed 全局 Permission Treehttp_path + http_method
    • 租戶建自訂 Role從 Tree 勾選 Permission自動補 parent
    • Casbin 以 (tenant_id, role_key, path, method) 比對,跨租戶同名角色互不污染
  5. 身份驗證 vs 業務驗證分層

    級別 由誰負責 範例
    身份級 ZITADEL Org Policy 登入 MFA、註冊 email、忘記密碼、帳號鎖定
    業務級 Gateway member 業務 email/phone OTP、TOTP step-up
    Gateway ZITADEL.email_verified 當業務守門;改讀 member.business_email_verified
  6. UseCase 原子性 UseCase 為 atomic primitive禁止互相呼叫跨原子流程OTP → 寄信 → 驗碼 → flip flag一律在 internal/logic/<module>/ 編排。


3. 模組依賴方向

handler → logic → model/{module}/domain/usecase介面
                       ↓
              model/{module}/repository介面
                       ↓
                MongoDB / Redis

logic 可同時呼叫多個 model 的 usecase編排
usecase 之間互不依賴
auth/logic   → member.usecaseCreateUnverified / Activate / EnsureFromOIDC
auth/logic   → permission.usecaseSyncRolesFromClaims未來
auth/logic   → notification.NotifierOTP / 註冊信)
member/logic → notification.Notifier業務驗證、step-up OTP
permission   → 獨立,不反向依賴

4. 外部系統分工

能力 ZITADEL auth member permission notification
OIDC / Social Login ? callback 換 JWT EnsureFromOIDC SyncRoles
平台 Email + Password 註冊 建 userlocal logic 編排 LifecycleUseCase 寄 OTP
身份 MFA 強制 ? Org Policy
LDAP 登入 ? LDAP IdP Group→Role
對外 JWT ? CloudEP
業務 TOTP (Authenticator) ? AES-GCM 存 secret
業務 Email/Phone OTP ? OTPUseCase ? 模板 + 發送
API 細粒度權限 粗 Role ? Casbin
SCIM Users/Groups 可同步 業務寫入 Group→Role
Directory Sync Worker Group→Role 同步異常告警

4.1 租戶 ? ZITADEL Org

1 CloudEP Tenant = 1 ZITADEL Organization = 1 資料隔離邊界
欄位 來源 用途
tenant_id Gateway 內部 分片鍵 / 授權邊界
tenant.org_id ZITADEL org_id 身份系統對應
member.zitadel_user_id ZITADEL sub 身份映射
member.uid UIDGenerator 業務可讀主鍵

4.2 Tenant 建立Saga

1. POST /api/v1/admin/tenants
   → Mongo upsert tenants { status: provisioning, org_id: "" }
2. ZITADEL Mgmt.CreateOrganization(slug)
   → org_id
3. UPDATE tenants { org_id, status: active }
4. seed system roles + Casbin reload
失敗補償cron 每 5 分鐘):
- 步驟 2 失敗 → status=failed指數退避3 次後告警
- 步驟 3 失敗 → status=orphan_zitadel_org掃描補綁

4.3 租戶類型

類型 登入 LDAP 權限
B2C Email / Social 系統預設 Role唯讀模板
B2B ZITADEL → LDAP IdP ? 完全自定義 Role + Permission
Hybrid Social + LDAP ? B2B 自定義;外部客戶用 B2C 模板

5. UID 設計

規則
格式 {TenantUIDPrefix}-{Sequence}
Prefix 2~4 個大寫字母Tenant 建立時設,全域唯一)
起始序號 10,000,0007 位起跳,避免 ACME-1 這種短 UID
唯一鍵 (tenant_id, uid)
範例 ACME-10000003

實作:member.UIDGenerator → Redis INCR member:seq:{tenant};首次 INCR=1 時自動 INCRBY 9_999_999 補到起跳值。


6. Permission 模型

平台層 (Platform-wide)            租戶層 (per-tenant)
┌────────────────┐               ┌─────────┐
│ Permission     │ ── 勾選 ──→   │ Role    │
│ Catalog (Tree) │               │         │
└────────────────┘               │  ↓ 指派  │
                                 │ UserRole│
                                 │         │
                                 │  ↑ 對映  │
                                 │RoleMap  │
                                 └─────────┘
                                      ↓ LoadPolicy
                            Casbin Enforcer (Redis adapter)
                                      ↓
                              CasbinRBAC Middleware
概念 說明
Permission 平台級節點(樹狀 dot notationName 不可改;廢棄走 status=close
Role 租戶內角色,(tenant_id, key) uniqueKey 不可改(外部 IdP mapping 直接綁 Key
RolePermission 全量取代式更新;自動補 parent permission
UserRole source 區分 manual / zitadel / ldap / scimReplaceForSource 不洗 manual
RoleMapping 外部 group/role → 內部 role.key,給 SyncFromX 翻譯 IdP claims
Casbin Rule [tenant, role.key, http_path, http_methods, perm.name]

多 pod 同步Redis Pub/Sub 即時 + 5 分鐘 cron 兜底(兜底建議在 svc 層排程,本模組不內建)。


7. Middleware 鏈

HTTP Request
   ↓
[AuthJWT]          ← 解析 Bearer → actor.WithActor(ctx, tenant, uid)
   ↓
[CasbinRBAC]       ← 必須在 AuthJWT 之後any-allow 過所有 open role
   ↓
handler → logic → usecase

掛載方式:在 .api@server (middleware: AuthJWT,CasbinRBAC) 宣告,make gen-api 會把 middleware 寫進 routes.go禁止gateway.goserver.Use(...) 全域掛。詳見 generate/api/README.md

Actor 一律用 internal/library/actor.WithActor / ActorFromContext,不要在各 logic package 自定 actorKey struct{}


8. Notification 與業務驗證

詳細:internal/model/notification/README.mdinternal/model/member/README.md

流程 編排層 用到的 atomic
平台註冊 email OTP logic/auth.RegisterLogic member.OTP.Generate + notifier.Send(verify_registration_email)
業務 email/phone 驗證 logic/member.startVerification + confirmVerification VerifyRateOTP.GenerateNotifier.SendProfile.SetXxxVerified
TOTP 綁定 / step-up logic/member.*_t_o_t_p_* TOTP.StartEnroll / ConfirmEnroll / VerifyCode

Notification 是 library-style domain由 ServiceContext 啟動 RetryWorker(異步重試 + DLQ。Provider chainSMTP / SES / Mitake / MockSort failover。


9. Rate Limit / Audit規劃

主題 現況 規劃
OTP / 業務驗證 cooldown ? 已實作(member.VerifyRateRedis SETNX + daily INCR
HTTP 全域 rate limit 未實作 建議 go-zero middleware + Redis sliding-windowZSETkey = rl:{dim}:{path}
Audit Log 未實作 audit_logs collection獨立 DB 建議);critical 同步寫,info 批次TTL 90d

10. 規模考量100 萬+ 會員)

項目 建議
members 分片 hashed tenant_id(單租戶 50 萬可走複合 unique index 不分片)
Casbin policy 一 tenant 一 enforcerlazy 建立Redis Set 儲存 rule
JWT 黑名單 只黑名單已撤銷的 jtiTTL = 至自然過期
Member list 查詢 強制帶 tenant_id + (create_at, _id) cursor 分頁
Notification DLQ 超過 MaxRetry 寫入 notification_dlqadmin CLI 重試

11. 已決策事項

主題 決策
Tenant 建立順序 Gateway 先建草稿status=provisioning→ ZITADEL CreateOrg → 補 org_id;補償 cron
Permission name 改名 禁止(被 RolePermission / Casbin policy.name 引用);廢棄改 status=close
Role.Key 改名 禁止(外部 IdP mapping 直接綁)
is_system Role 不可刪、不可改 status
manual source ReplaceForSource 拒絕(防 SyncFromX 誤洗手動指派)
Gateway 統一註冊 取代 ZITADEL Hosted Pageemail + social 同 UXinvite 由 logic 驗
Email / SMS OTP 由 Gateway notification 自送,轉 ZITADEL Notification
業務 TOTP 與 ZITADEL TOTP 獨立secret AES-GCM 存 Mongo
Email 驗證守門 member.business_email_verified讀 ZITADEL email_verified
UseCase 不互呼 強制:跨原子流程在 logic 編排model.md §6.1
Casbin 多 pod 同步 Redis Pub/Sub 即時 + 5min cron 兜底
Permission Catalog 變更 seed CLIcmd/permission-seedUI 不可直接改

12. 目錄結構

internal/
├── library/
│   ├── actor/        # ctx actor helper跨 module 共用 key
│   ├── crypto/       # AES-GCM cipherTOTP secret KEK
│   ├── errors/       # 8 碼 SSCCCDDD
│   ├── mongo/        # DocumentDB + cache
│   ├── redis/        # go-zero client + Pub/Sub
│   ├── validate/     # struct 驗證
│   └── zitadel/      # ZITADEL HTTP client
├── middleware/
│   ├── authjwt_middleware.go     # 解 JWT → actor
│   └── casbinrbac_middleware.go  # any-allow RBAC
├── model/
│   ├── auth/         # 邀請碼 / 註冊 metadata / OAuth session / JWT
│   ├── member/       # Tenant / Member / Identity / OTP / TOTP / UID
│   ├── notification/ # Email / SMS / 模板 / Worker / DLQ
│   └── permission/   # Permission Catalog / Role / RolePermission / Casbin
└── worker/
    └── notification_retry/       # Notification RetryWorker runner

13. 設定檔

主要區塊(完整見 etc/README.md + etc/gateway.dev.example.yaml

Mongo: {...}
Redis: {...}
Auth:        # JWT secret / TTL / RegistrationSessionTTLSeconds
Member:      # OTP / TOTP / Registration
Permission:  # Casbin.Enabled / ModelPath / PolicyAdapter / Cache / Reload
Notification:# Email / SMS / Async / RatePerTenant
Zitadel:    # Issuer / ServiceUserToken / Google* / DefaultOrgID

14. 進度速覽

模組 狀態 備註
auth ? 已實作 統一註冊 (Email + Google) / login / token refresh / logout
member ? 已實作 profile / 業務 email/phone OTP / TOTP 全流程
permission ? 已實作 Catalog / Role CRUD / RolePermission / UserRole / RoleMapping / Casbin RBAC
notification ? 核心完成 Email/SMS sync+async + DLQHTTP admin API 未做
LDAP Directory Sync ? 未實作 依 SCIM / SyncFromX 推進
SCIM 2.0 server ? 未實作 依企業客戶需求
Audit Log ? 未實作 規劃 collection + TTL 90d
HTTP Rate Limit middleware ? 未實作 OTP cooldown 已有;全域待補