9.9 KiB
9.9 KiB
Auth Service
Auth Service — SRS/SDD Document
| Version | Version Date | Editor | Memo |
|---|---|---|---|
| 1.0.0 | 2026/05/21 | Gateway Team | 初版:Gateway Auth 模組 SDD |
1. Introduction
1.1 Purpose
Auth 模組為 TianTing Gateway 的認證領域層,提供租戶範圍內的原子化認證原語:邀請碼、註冊稽核、OAuth 暫存 Session、CloudEP JWT 簽發/刷新/登出。完整 HTTP 流程由 internal/logic/auth/ 編排,並與 ZITADEL(身份)、Member(會員)、Notification(通知)協作。
1.2 Scope
範圍內:
- 租戶邀請碼(Validate / Consume)
- 註冊稽核 metadata(條款版本、渠道、行銷 opt-in)
- OAuth 社交註冊/登入暫存 Session(Redis)
- CloudEP JWT access / refresh token 生命週期
- JWT 黑名單與 jti pair 管理
範圍外(委派其他模組):
- 使用者身份建立 → ZITADEL
- 會員 profile、OTP → Member 模組
- 郵件/簡訊 → Notification 模組
- RBAC 授權 → Permission 模組 + Casbin middleware
1.3 Definitions, Acronyms, and Abbreviation
| 縮寫 | 說明 |
|---|---|
| JWT | JSON Web Token,CloudEP 自簽 access / refresh token |
| JTI | JWT ID,用於黑名單與 pair 映射 |
| ROPG | Resource Owner Password Grant,密碼登入 |
| OIDC | OpenID Connect,社交登入/SSO |
| OTP | One-Time Password,由 Member 模組管理 |
| Tenant | 租戶,多租戶隔離單位 |
| UID | 租戶內可讀會員識別碼(如 ACME-10000003) |
1.4 Technologies to be used
| 項目 | 技術 |
|---|---|
| Application Language | Go 1.22+ |
| Framework | go-zero (rest, logx, stores/redis) |
| Cache / Session | Redis |
| Database | MongoDB |
| JWT | github.com/golang-jwt/jwt/v4(HS256) |
| Identity Provider | ZITADEL(internal/library/zitadel) |
| API Codegen | goctl / .api 檔 |
1.5 Overview
Auth 模組採 Clean Architecture 分層:domain/ 定義介面與實體,repository/ 實作 Mongo / Redis 適配器,usecase/ 提供原子 UseCase。HTTP handler 不直接存取 repository,而是由 logic 層串接 ZITADEL + Member + Auth 原語。
主要流程:
- Email 註冊:Consume invite → ZITADEL 建 user → Member 建 unverified → 發 OTP → confirm 後 Activate + IssuePair
- 密碼登入:ZITADEL ROPG → 查 Member → IssuePair
- 社交註冊/登入:Redis Session 暫存 OAuth state → callback 換 token → Provision / Login
- Token 刷新/登出:Refresh 黑名單舊 pair 後重簽;Logout 黑名單 access + refresh jti
2. System Overview
Auth 模組是 Gateway 認證子系統的核心,負責:
- 控制誰可以註冊(邀請碼)
- 記錄註冊合規稽核
- 管理短期 OAuth 流程狀態
- 簽發與驗證 CloudEP JWT(middleware
AuthJWT)
對外透過 /api/v1/auth/* REST API 暴露;JWT 驗證後將 (tenant_id, uid) 注入 request context,供 Member / Permission 等下游使用。
3. System Architecture
3.1 System Architecture
flowchart TB
subgraph Client["Client / Frontend"]
Web[Web / Mobile App]
end
subgraph Gateway["Gateway"]
Handler["handler/auth"]
Logic["logic/auth<br/>(orchestration)"]
subgraph AuthModule["internal/model/auth"]
UC["usecase/"]
Repo["repository/"]
Domain["domain/"]
end
MW["middleware/AuthJWT"]
end
subgraph External["External Services"]
Zitadel[ZITADEL IdP]
Mongo[(MongoDB)]
Redis[(Redis)]
end
subgraph Sibling["Sibling Modules"]
Member[member]
Notif[notification]
end
Web --> Handler
Handler --> Logic
Logic --> UC
Logic --> Zitadel
Logic --> Member
Logic --> Notif
UC --> Repo
Repo --> Mongo
Repo --> Redis
MW --> UC
3.2 Decomposition Description
| 套件 | 職責 |
|---|---|
config/ |
JWT TTL、Session TTL 設定 |
domain/entity/ |
Mongo 文件模型(InviteCode、RegistrationMetadata) |
domain/enum/ |
RegistrationChannel(email / google) |
domain/repository/ |
Port 介面 + Redis Session struct |
domain/usecase/ |
UseCase 介面 + DTO |
domain/const.go |
BSON 欄位名、Redis key、邀請碼 hash helper |
domain/errors.go |
領域 sentinel errors |
repository/ |
Mongo + Redis 適配器、EnsureMongoIndexes |
usecase/ |
實作 + NewModuleFromParam factory |
usecase/module.go |
組裝 Invite / RegistrationMeta / Session UseCase |
ServiceContext 注入:
| 欄位 | UseCase | 條件 |
|---|---|---|
AuthInvite |
InviteUseCase | Mongo + Redis |
AuthRegistrationMeta |
RegistrationMetaUseCase | Mongo |
AuthRegistrationSession |
RegistrationSessionUseCase | Redis |
AuthLoginSession |
LoginSessionUseCase | Redis |
AuthToken |
TokenUseCase | JWT secret + Redis(獨立於 Module) |
3.3 Token
CloudEP JWT 採 HS256,access / refresh 使用不同 secret。
Claims 結構:
| Claim | 說明 |
|---|---|
tenant_id |
租戶 ID |
uid |
會員 UID |
typ |
access 或 refresh |
auth_gen |
簽發世代(用於強制登出) |
jti |
Token 唯一 ID |
iat / exp |
簽發/過期時間 |
預設 TTL:
| Token | 預設 |
|---|---|
| Access | 900 秒(15 分鐘) |
| Refresh | 604800 秒(7 天) |
| Registration Session | 600 秒(10 分鐘) |
Redis 映射:
| Key | 用途 |
|---|---|
auth:jwt:pair:{jti} |
access ↔ refresh jti 雙向映射 |
auth:jwt:bl:{jti} |
已登出/已刷新的 jti 黑名單 |
Refresh 流程:
sequenceDiagram
participant C as Client
participant L as TokenRefreshLogic
participant T as TokenUseCase
participant R as Redis
C->>L: POST /auth/token/refresh {refresh_token}
L->>T: Refresh(refreshToken)
T->>T: Parse + verify typ=refresh
T->>R: Blacklist old refresh jti + paired access jti
T->>T: IssuePair(new access + refresh)
T->>R: SavePair(new jti mapping)
T-->>L: TokenPair
L-->>C: AuthTokenData
3.4 Invite Code
邀請碼以 SHA-256 hash 儲存,明文永不落庫。
| 操作 | 行為 |
|---|---|
| Validate | 依 (tenant_id, code_hash) 查詢,檢查過期與剩餘次數 |
| Consume | Redis SETNX lock(30s)→ 原子 $inc used_count |
消費時機:
- Email 註冊:在
/register起始即 Consume - 社交註冊:Start 僅 Validate;Callback 才 Consume
3.5 OAuth Session
| Session 類型 | Redis Key | State 前綴 | 用途 |
|---|---|---|---|
| Registration | auth:register:session:{id} |
reg: |
社交註冊暫存 invite / terms |
| Login | auth:login:session:{id} |
login: |
社交登入暫存 tenant / redirect |
4. Data Design
4.1 Data Dictionary
invite_codes(MongoDB)
| Field | Type | Comment | Index |
|---|---|---|---|
| _id | ObjectId | PK | PK |
| tenant_id | String | 租戶 ID | Unique(tenant_id, code_hash) |
| code_hash | String | SHA-256(normalized code) | Unique(tenant_id, code_hash) |
| max_uses | Int64 | 最大可用次數 | — |
| used_count | Int64 | 已使用次數 | — |
| expires_at | Int64 | 過期時間 ms(0=永不過期) | — |
| new_users_only | Bool | 僅限新用戶(社交註冊) | — |
| create_at | Int64 | 建立時間 ms | — |
| update_at | Int64 | 更新時間 ms | — |
registration_metadata(MongoDB)
| Field | Type | Comment | Index |
|---|---|---|---|
| _id | ObjectId | PK | PK |
| tenant_id | String | 租戶 ID | Unique(tenant_id, uid) |
| uid | String | 會員 UID | Unique(tenant_id, uid) |
| invite_code_id | String | 使用的邀請碼 ID | — |
| accept_terms_version | String | 接受的服務條款版本 | — |
| marketing_opt_in | Bool | 行銷 opt-in | — |
| registration_channel | String | email / google | — |
| client_ip | String | 註冊 IP | — |
| user_agent | String | User-Agent | — |
| occurred_at | Int64 | 事件時間 ms | — |
| create_at | Int64 | 建立時間 ms | — |
Redis Session / Token Keys
| Key Pattern | Type | TTL | Comment |
|---|---|---|---|
| auth:register:session:{id} | String(JSON) | 600s | 社交註冊 OAuth session |
| auth:login:session:{id} | String(JSON) | 600s | 社交登入 OAuth session |
| auth:invite:consume:{tenant}:{hash} | String | 30s | 邀請碼消費鎖 |
| auth:jwt:pair:{jti} | String | token TTL | access↔refresh 映射 |
| auth:jwt:bl:{jti} | String | 至自然過期 | JWT 黑名單 |
5. API Design
Base Path: /api/v1/auth
5.1 Public Endpoints(無 Bearer)
| Method | Path | 說明 |
|---|---|---|
| POST | /register |
Email 註冊(回傳 challenge_id) |
| POST | /register/confirm |
OTP 確認 → 核發 JWT |
| POST | /register/resend |
重發註冊 OTP |
| POST | /register/social/start |
社交註冊 OAuth 起始 |
| GET | /register/social/callback |
社交註冊 OAuth callback |
| POST | /login |
密碼登入 |
| POST | /login/social/start |
社交登入 OAuth 起始 |
| GET | /login/social/callback |
社交登入 OAuth callback |
| POST | /token/refresh |
刷新 token pair |
| POST | /token/exchange |
ZITADEL id_token → CloudEP JWT |
5.2 Protected Endpoints(需 Bearer JWT)
| Method | Path | 說明 |
|---|---|---|
| POST | /logout |
登出(黑名單 jti) |
完整請求/回應 schema 見 generate/api/auth.api;成功 envelope code=102000。
6. Resource
| 資源 | 路徑 |
|---|---|
| API 定義 | generate/api/auth.api |
| Logic 編排 | internal/logic/auth/ |
| JWT Middleware | internal/middleware/authjwt_*.go |
| 模組原始碼 | internal/model/auth/ |
| 設定範例 | etc/gateway.dev.example.yaml → Auth / JWT 區塊 |
| 設計參考 | docs/identity-member-design.md |