feat(api): add /auth/whoami endpoint and build automation

This commit is contained in:
2025-12-25 14:54:52 +08:00
parent 8e6d86edd7
commit 30f15a84b5
7 changed files with 397 additions and 1 deletions

1
.gitignore vendored
View File

@@ -30,3 +30,4 @@ go.work.sum
# Editor/IDE # Editor/IDE
# .idea/ # .idea/
# .vscode/ # .vscode/
ez-api

View File

@@ -1,12 +1,17 @@
FROM golang:1.24-alpine AS builder FROM golang:1.24-alpine AS builder
# Install make for Makefile support
RUN apk add --no-cache make
WORKDIR /app WORKDIR /app
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN go build -o ez-api ./cmd/server
# Use Makefile to generate swagger and build
RUN make build
FROM alpine:latest FROM alpine:latest

58
Makefile Normal file
View File

@@ -0,0 +1,58 @@
.PHONY: all build swagger test clean dev
# Default target
all: swagger build
# Generate swagger documentation using go run (no install needed)
swagger:
@echo "Generating Swagger documentation..."
go run github.com/swaggo/swag/cmd/swag@latest init -g cmd/server/main.go -o docs --parseDependency --parseInternal
# Build the binary
build: swagger
@echo "Building ez-api..."
go build -o ez-api ./cmd/server
# Build without swagger regeneration (for quick iteration)
build-fast:
go build -o ez-api ./cmd/server
# Run tests
test:
go test -v ./...
# Clean build artifacts
clean:
rm -f ez-api
rm -rf docs/
# Run in development mode
dev: swagger
go run ./cmd/server
# Format code
fmt:
go fmt ./...
# Lint code
lint:
@which golangci-lint > /dev/null || go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
golangci-lint run
# Generate swagger only (alias)
docs: swagger
# Help
help:
@echo "Available targets:"
@echo " all - Generate swagger docs and build (default)"
@echo " build - Generate swagger and build binary"
@echo " build-fast - Build binary without swagger regeneration"
@echo " swagger - Generate Swagger documentation"
@echo " docs - Alias for swagger"
@echo " test - Run tests"
@echo " dev - Run in development mode"
@echo " clean - Remove build artifacts"
@echo " fmt - Format code"
@echo " lint - Run linter"
@echo " help - Show this help"

View File

@@ -17,8 +17,30 @@
| :--- | :--- | :--- | :--- | | :--- | :--- | :--- | :--- |
| **Admin** | `Authorization: Bearer <admin_token>` | 环境变量 `EZ_ADMIN_TOKEN` | 全局管理权限,可管理所有租户、供应商和模型。 | | **Admin** | `Authorization: Bearer <admin_token>` | 环境变量 `EZ_ADMIN_TOKEN` | 全局管理权限,可管理所有租户、供应商和模型。 |
| **Master** | `Authorization: Bearer <master_key>` | 创建 Master 时返回 | 租户级权限,仅能管理所属的子 Key、查看自身统计和日志。 | | **Master** | `Authorization: Bearer <master_key>` | 创建 Master 时返回 | 租户级权限,仅能管理所属的子 Key、查看自身统计和日志。 |
| **Key** | `Authorization: Bearer <child_key>` | Master 或 Admin 签发 | 用于调用 AI API可通过 `/auth/whoami` 查询身份信息。 |
| **Internal** | `X-Internal-Token: <token>` | 环境变量 `EZ_INTERNAL_STATS_TOKEN` | 内部组件(如 Data Plane同步指标使用。 | | **Internal** | `X-Internal-Token: <token>` | 环境变量 `EZ_INTERNAL_STATS_TOKEN` | 内部组件(如 Data Plane同步指标使用。 |
### 1.4 身份识别接口
使用 `GET /auth/whoami` 可根据 Authorization header 中的 Token 识别当前身份类型:
| Token 类型 | 返回 `type` | 说明 |
| :--- | :--- | :--- |
| Admin Token | `"admin"` | 进入管理员面板 |
| Master Key | `"master"` | 进入租户自服务面板 |
| Child Key | `"key"` | 显示 Key 信息页,包含 `issued_by` 字段标识签发者 |
**示例响应**
```json
// Admin Token
{"type": "admin", "role": "admin"}
// Master Key
{"type": "master", "id": 1, "name": "研发团队", "group": "default", ...}
// Child Key
{"type": "key", "id": 5, "master_id": 1, "issued_by": "master", ...}
```
### 1.3 通用约定 ### 1.3 通用约定
- **分页处理** - **分页处理**
- 管理端列表 (`GET /admin/*`):使用 `page` (从 1 开始) 和 `limit` (默认 50最大 200)。 - 管理端列表 (`GET /admin/*`):使用 `page` (从 1 开始) 和 `limit` (默认 50最大 200)。
@@ -106,6 +128,9 @@ graph TD
## 4. API 模块概览 ## 4. API 模块概览
### 4.0 公开接口 (Auth API) - 无需中间件
- **身份识别**`GET /auth/whoami` - 根据 Token 返回身份类型和详细信息。
### 4.1 管理端 (Admin API) - 需 Admin Token ### 4.1 管理端 (Admin API) - 需 Admin Token
- **租户管理**:创建 Master、签发子 Key、实时 QPS 监控、冻结/解冻。 - **租户管理**:创建 Master、签发子 Key、实时 QPS 监控、冻结/解冻。
- **上游管理**ProviderGroup + APIKey 的 CRUD 与批量操作。 - **上游管理**ProviderGroup + APIKey 的 CRUD 与批量操作。

View File

@@ -2859,6 +2859,40 @@ const docTemplate = `{
} }
} }
}, },
"/auth/whoami": {
"get": {
"security": [
{
"AdminAuth": []
},
{
"MasterAuth": []
}
],
"description": "Returns the identity of the authenticated user based on the Authorization header.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\n\nResponse varies by token type:\n- Admin Token: {\"type\": \"admin\", \"role\": \"admin\"}\n- Master Key: {\"type\": \"master\", \"id\": 1, \"name\": \"...\", ...}\n- Child Key: {\"type\": \"key\", \"id\": 5, \"master_id\": 1, \"issued_by\": \"master\", ...}",
"produces": [
"application/json"
],
"tags": [
"auth"
],
"summary": "Get current identity",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/internal_api.WhoamiResponse"
}
},
"401": {
"description": "Invalid or missing token",
"schema": {
"$ref": "#/definitions/gin.H"
}
}
}
}
},
"/internal/stats/flush": { "/internal/stats/flush": {
"post": { "post": {
"description": "Internal endpoint for flushing accumulated key usage stats from DP to CP database", "description": "Internal endpoint for flushing accumulated key usage stats from DP to CP database",
@@ -4620,6 +4654,83 @@ const docTemplate = `{
} }
} }
}, },
"internal_api.WhoamiResponse": {
"type": "object",
"properties": {
"created_at": {
"type": "integer",
"example": 1703505600
},
"default_namespace": {
"type": "string",
"example": "default"
},
"epoch": {
"type": "integer",
"example": 1
},
"global_qps": {
"type": "integer",
"example": 100
},
"group": {
"type": "string",
"example": "default"
},
"id": {
"description": "Master fields (only present when type is \"master\")",
"type": "integer",
"example": 1
},
"issued_at_epoch": {
"type": "integer",
"example": 1
},
"issued_by": {
"type": "string",
"example": "master"
},
"master_id": {
"description": "Key fields (only present when type is \"key\")",
"type": "integer",
"example": 1
},
"max_child_keys": {
"type": "integer",
"example": 5
},
"name": {
"type": "string",
"example": "tenant-a"
},
"namespaces": {
"type": "string",
"example": "default,ns1"
},
"role": {
"description": "Admin fields (only present when type is \"admin\")",
"type": "string",
"example": "admin"
},
"scopes": {
"type": "string",
"example": "chat:write"
},
"status": {
"type": "string",
"example": "active"
},
"type": {
"description": "Type of the authenticated identity: \"admin\", \"master\", or \"key\"",
"type": "string",
"example": "master"
},
"updated_at": {
"type": "integer",
"example": 1703505600
}
}
},
"internal_api.refreshModelRegistryRequest": { "internal_api.refreshModelRegistryRequest": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -2853,6 +2853,40 @@
} }
} }
}, },
"/auth/whoami": {
"get": {
"security": [
{
"AdminAuth": []
},
{
"MasterAuth": []
}
],
"description": "Returns the identity of the authenticated user based on the Authorization header.\nSupports Admin Token, Master Key, and Child Key (API Key) authentication.\n\nResponse varies by token type:\n- Admin Token: {\"type\": \"admin\", \"role\": \"admin\"}\n- Master Key: {\"type\": \"master\", \"id\": 1, \"name\": \"...\", ...}\n- Child Key: {\"type\": \"key\", \"id\": 5, \"master_id\": 1, \"issued_by\": \"master\", ...}",
"produces": [
"application/json"
],
"tags": [
"auth"
],
"summary": "Get current identity",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/internal_api.WhoamiResponse"
}
},
"401": {
"description": "Invalid or missing token",
"schema": {
"$ref": "#/definitions/gin.H"
}
}
}
}
},
"/internal/stats/flush": { "/internal/stats/flush": {
"post": { "post": {
"description": "Internal endpoint for flushing accumulated key usage stats from DP to CP database", "description": "Internal endpoint for flushing accumulated key usage stats from DP to CP database",
@@ -4614,6 +4648,83 @@
} }
} }
}, },
"internal_api.WhoamiResponse": {
"type": "object",
"properties": {
"created_at": {
"type": "integer",
"example": 1703505600
},
"default_namespace": {
"type": "string",
"example": "default"
},
"epoch": {
"type": "integer",
"example": 1
},
"global_qps": {
"type": "integer",
"example": 100
},
"group": {
"type": "string",
"example": "default"
},
"id": {
"description": "Master fields (only present when type is \"master\")",
"type": "integer",
"example": 1
},
"issued_at_epoch": {
"type": "integer",
"example": 1
},
"issued_by": {
"type": "string",
"example": "master"
},
"master_id": {
"description": "Key fields (only present when type is \"key\")",
"type": "integer",
"example": 1
},
"max_child_keys": {
"type": "integer",
"example": 5
},
"name": {
"type": "string",
"example": "tenant-a"
},
"namespaces": {
"type": "string",
"example": "default,ns1"
},
"role": {
"description": "Admin fields (only present when type is \"admin\")",
"type": "string",
"example": "admin"
},
"scopes": {
"type": "string",
"example": "chat:write"
},
"status": {
"type": "string",
"example": "active"
},
"type": {
"description": "Type of the authenticated identity: \"admin\", \"master\", or \"key\"",
"type": "string",
"example": "master"
},
"updated_at": {
"type": "integer",
"example": 1703505600
}
}
},
"internal_api.refreshModelRegistryRequest": { "internal_api.refreshModelRegistryRequest": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -731,6 +731,64 @@ definitions:
description: active/suspended description: active/suspended
type: string type: string
type: object type: object
internal_api.WhoamiResponse:
properties:
created_at:
example: 1703505600
type: integer
default_namespace:
example: default
type: string
epoch:
example: 1
type: integer
global_qps:
example: 100
type: integer
group:
example: default
type: string
id:
description: Master fields (only present when type is "master")
example: 1
type: integer
issued_at_epoch:
example: 1
type: integer
issued_by:
example: master
type: string
master_id:
description: Key fields (only present when type is "key")
example: 1
type: integer
max_child_keys:
example: 5
type: integer
name:
example: tenant-a
type: string
namespaces:
example: default,ns1
type: string
role:
description: Admin fields (only present when type is "admin")
example: admin
type: string
scopes:
example: chat:write
type: string
status:
example: active
type: string
type:
description: 'Type of the authenticated identity: "admin", "master", or "key"'
example: master
type: string
updated_at:
example: 1703505600
type: integer
type: object
internal_api.refreshModelRegistryRequest: internal_api.refreshModelRegistryRequest:
properties: properties:
ref: ref:
@@ -2612,6 +2670,33 @@ paths:
summary: Test dependency connectivity summary: Test dependency connectivity
tags: tags:
- system - system
/auth/whoami:
get:
description: |-
Returns the identity of the authenticated user based on the Authorization header.
Supports Admin Token, Master Key, and Child Key (API Key) authentication.
Response varies by token type:
- Admin Token: {"type": "admin", "role": "admin"}
- Master Key: {"type": "master", "id": 1, "name": "...", ...}
- Child Key: {"type": "key", "id": 5, "master_id": 1, "issued_by": "master", ...}
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/internal_api.WhoamiResponse'
"401":
description: Invalid or missing token
schema:
$ref: '#/definitions/gin.H'
security:
- AdminAuth: []
- MasterAuth: []
summary: Get current identity
tags:
- auth
/internal/stats/flush: /internal/stats/flush:
post: post:
consumes: consumes: