From 8bbab98231a76956038b089543077fac9b5b662f Mon Sep 17 00:00:00 2001 From: wolves Date: Sun, 25 Jan 2026 18:03:07 +0800 Subject: [PATCH] =?UTF-8?q?infra=E6=96=87=E4=BB=B6=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- README.md | 8 ++++ docker-compose.yml | 58 +++++++++++++++++++++++++ docs/subModule/iam.md | 98 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index b0d6d66..3050798 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ .idea -.DS_Store \ No newline at end of file +.DS_Store + +data/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e5d8e28 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# superToDo + +> A to-do list app , but with complaxible backend. + +> 项目包含以下子项目: +- 认证服务 +- 文档 +- ai快速原型认证子项目 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..aea930a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,58 @@ +services: + postgres: + image: postgres:18 + container_name: todo-postgres + environment: + POSTGRES_USER: todo + POSTGRES_PASSWORD: todo + POSTGRES_DB: todo + ports: + - "5432:5432" + volumes: + - ./data/pgsql:/var/lib/postgresql + + redis: + image: redis:8.4 + container_name: todo-redis + ports: + - "6379:6379" + volumes: + - ./data/redis:/data + + kafka: + image: apache/kafka:4.1.1 + container_name: kafka + ports: + - "29092:29092" + environment: + # KRaft: broker + controller + KAFKA_NODE_ID: "1" + KAFKA_PROCESS_ROLES: "broker,controller" + KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093" + + # listeners + KAFKA_LISTENERS: "PLAINTEXT://0.0.0.0:9092,PLAINTEXT_HOST://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093" + # 容器内访问使用 kafka:9092,本机访问使用 localhost:29092 + KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092" + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT,CONTROLLER:PLAINTEXT" + KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER" + KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT" + + # 单节点开发用 + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" + KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: "1" + KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: "1" + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: "0" + volumes: + - ./data/kafka:/var/lib/kafka/data + + kafka-ui: + image: provectuslabs/kafka-ui:latest + container_name: todo-kafka-ui + ports: + - "8081:8080" + environment: + KAFKA_CLUSTERS_0_NAME: local + KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 + depends_on: + - kafka diff --git a/docs/subModule/iam.md b/docs/subModule/iam.md index 344e8b0..688f80a 100644 --- a/docs/subModule/iam.md +++ b/docs/subModule/iam.md @@ -1 +1,99 @@ # 认证服务 + +```mermaid +flowchart TB + U[User / Client] -->|login| GW[API Gateway] + GW -->|auth request| IAM[IAM Auth Service] + IAM -->|issue tokens| GW + GW -->|return tokens| U + + U -->|API request with access token| GW + GW -->|forward request| T[Todo Service] + + subgraph IAM_Core[IAM Core] + IAM --> KMS[Key Store] + IAM --> JWKS[JWKS Endpoint] + IAM --> RT[Refresh Token Store] + IAM --> IDP[User Org Role Store] + end + + T -->|fetch public keys| JWKS + T -->|verify JWT locally| T + T -->|resource authorization| DB[Todo Database] + + T -->|optional version or revoke check| R[Redis Cache] + IAM -->|update version or revoke| R + + T -->|emit events| MQ[Kafka] + MQ --> N[Notification Service] + MQ --> S[Search Service] +``` + +```mermaid +sequenceDiagram + autonumber + participant C as Client + participant GW as API Gateway + participant IAM as IAM/Auth + participant JWKS as JWKS Endpoint + participant T as Task Service + participant DB as Postgres + participant R as Redis(ver/jti) + + %% Login + C->>GW: POST /auth/login (username/password) + GW->>IAM: forward /auth/login + IAM->>IAM: validate credentials + IAM->>IAM: issue access_token(JWT) + refresh_token + IAM->>GW: 200 tokens + GW->>C: 200 tokens (store refresh safely) + + %% Normal API call (local verify) + C->>GW: GET /tasks (Authorization: Bearer access) + GW->>T: forward request (+ traceId) + + alt JWKS cache miss + T->>JWKS: GET /.well-known/jwks.json + JWKS-->>T: public keys + end + + T->>T: verify JWT signature + iss/aud/exp + opt fast invalidation check (recommended) + T->>R: GET auth_ver:{sub} or revoked_jti:{jti} + R-->>T: ok / mismatch + end + T->>DB: query tasks WHERE tenant_id=tid AND (owner=sub OR permission) + DB-->>T: tasks + T-->>GW: 200 tasks + GW-->>C: 200 tasks + + %% Access expired -> refresh + C->>GW: GET /tasks (access expired) + GW-->>C: 401 token_expired + C->>GW: POST /auth/refresh (refresh_token) + GW->>IAM: forward refresh + IAM->>IAM: validate refresh token (rotation/reuse detection) + IAM->>IAM: issue new access + new refresh + IAM-->>GW: 200 new tokens + GW-->>C: 200 new tokens + C->>GW: retry GET /tasks (new access) + GW->>T: forward + T->>T: verify JWT ... + T->>DB: query ... + DB-->>T: tasks + T-->>GW: 200 + GW-->>C: 200 + + %% Role change / revoke (how to take effect) + Note over IAM,R: Admin changes role OR user logs out\nIAM increments auth_ver or revokes jti + IAM->>R: SET auth_ver:{sub}=newVersion OR SET revoked_jti:{jti}=1 + + %% After role change + C->>GW: POST /tasks (Authorization: Bearer old access) + GW->>T: forward + T->>T: verify JWT ok (signature still valid) + T->>R: GET auth_ver:{sub} / revoked_jti:{jti} + R-->>T: mismatch / revoked + T-->>GW: 401/403 (reauth required) + GW-->>C: 401/403 +``` \ No newline at end of file