AI_PROJECT_GUIDE.md
Rama main · réplica de lectura del repositorio original.
# OIDC Platform AI 快速上手技术文档
> 目标:让后续接手的 AI 或工程师不需要从零扫完整仓库,就能理解项目边界、数据流、模块关系、常见修改入口和验证方式。
## 1. 项目一句话定位
这是一个自托管 OIDC / OAuth2 身份认证平台。用户在平台内通过邮箱注册登录,并绑定 GitHub、Google、GitLab、Gitee、Discord、Microsoft、Apple、Telegram、QQ、微信、手机号、自定义 OAuth2 等身份来源来提升“信任等级”。下游业务系统只需要接入本平台的标准 OIDC 端点,并配置最低信任等级、邮箱验证要求和访问规则,即可获得统一认证、准入控制和基础风控能力。
核心产品形态:
- 用户中心:注册、登录、找回密码、邮箱验证、社交绑定、会话、授权应用、Passkey、信任等级查看。
- 开发者门户:创建 OIDC 客户端、管理密钥和回调地址、查看授权用户、举报/拉黑用户。
- 管理后台:用户、客户端、Provider、信任等级规则、系统设置、审计日志、签名密钥、风控列表。
- 标准协议服务:`/.well-known/openid-configuration`、`/oauth2/authorize`、`/oauth2/token`、`/oauth2/userinfo`、`/jwks.json`。
## 2. 技术栈和运行命令
### 后端
- 语言:Go `1.25.6`,module 为 `github.com/anthropic/oidc-platform`。
- HTTP 路由:`chi`。
- OIDC/OAuth2 引擎:`ory/fosite`。
- 配置:`viper`,支持 YAML + `OIDC_*` 环境变量覆盖。
- 存储:SQLite 或 PostgreSQL。
- 缓存:SQLite 模式默认内存缓存;PostgreSQL 模式使用 Redis。
- Passkey:`go-webauthn/webauthn`。
- 密码:Argon2id。
### 前端
- Vue 3 + Vite + TypeScript + Pinia + Vue Router + Vue I18n。
- API 统一走 `/api/v1`,fetch 带 `credentials: 'same-origin'`。
### 常用命令
```bash
# 后端测试
go test ./...
# 后端格式化
gofmt -w <go files>
# 前端构建
cd frontend && npm run build
# 前端开发
cd frontend && npm run dev
# 构建后端二进制
go build -o oidc-platform ./cmd/server
# Docker Compose 启动 Postgres + Redis + App
cp .env.example .env
docker compose up --build
```
### 当前已验证命令
最近一次验证已通过:
```bash
go test ./...
cd frontend && npm run build
```
## 3. 目录地图
```text
cmd/server/ 服务启动入口、依赖注入、种子数据、后台任务
configs/ YAML 配置,含 config.yaml / config.sqlite.yaml
db/migrations/ 数据库迁移,PostgreSQL 风格;SQLite 适配器内有兼容迁移执行
db/queries/ sqlc 查询定义,当前仓库实际主要使用手写 repository
frontend/ Vue 3 SPA
internal/adapter/ 外部系统和基础设施适配层
memcache/ 内存缓存
redis/ Redis 缓存
smtp/ 邮件发送
social/ 第三方 OAuth/OIDC Provider
sqlite/ SQLite 仓储实现
postgres/ PostgreSQL 仓储实现
internal/config/ 配置结构和加载逻辑
internal/domain/ 领域数据结构
internal/handler/ HTTP handler 和中间件
internal/oidcprovider/ fosite 封装、OIDC session/claims
internal/port/ 接口边界:repository、cache、email、social provider 等
internal/router/ HTTP 路由总表
internal/service/ 业务服务层
```
前端目录:
```text
frontend/src/api/client.ts API 包装
frontend/src/router/index.ts 路由和权限守卫
frontend/src/stores/auth.ts 登录态、用户信息、开发者权限
frontend/src/i18n/ 中英文文案
frontend/src/layouts/ 公开页、登录页、用户中心、开发者、管理员布局
frontend/src/pages/ 页面组件
frontend/src/composables/ 公共组合逻辑,如 public config、Turnstile、密码策略
```
## 4. 运行时组装关系
启动入口:`cmd/server/main.go`。
核心流程:
```mermaid
flowchart TD
A[config.Load] --> B[bootstrap]
B --> C[选择数据库: sqlite/postgres]
C --> D[初始化 repo/cache]
D --> E[Social Registry]
E --> F[Service 层]
F --> G[OIDC Provider]
G --> H[Handler 层]
H --> I[router.NewRouter]
I --> J[HTTP Server]
```
`cmd/server/bootstrap.go` 做了大部分运行时组装:
- 根据 `database.driver` 选择 SQLite 或 PostgreSQL。
- SQLite:`internal/adapter/sqlite` + `memcache`。
- PostgreSQL:`internal/adapter/postgres` + `redis`。
- 初始化所有 repository。
- 初始化 `SecretCipher`,用于客户端密钥加密。
- 初始化 Social Provider Registry。
- 初始化 SMTP sender。
- 初始化业务服务。
- 初始化 Passkey/WebAuthn。
- 加载或创建 RSA signing key。
- 创建 fosite OAuth2/OIDC provider。
- 创建所有 handler。
- 启动后台任务。
- 种子管理员、Provider 配置、全局设置。
- 找到 `frontend/dist` 并交给 SPA handler。
后台任务:
- 每 15 分钟清理过期用户 session。
- 每 1 小时重算全部用户信任等级。
- 如果 `social_auth_sync.enabled=true`,定期同步第三方绑定授权状态。
## 5. 配置模型
配置入口:`internal/config/config.go`。
加载规则:
- 配置文件名:`config.yaml`。
- 搜索路径:`./configs`、`.`、`/etc/oidc`。
- 环境变量前缀:`OIDC_`。
- `.` 会映射为 `_`,如 `server.public_url` 可由 `OIDC_SERVER_PUBLIC_URL` 覆盖。
关键配置:
```text
server.host / port / public_url / issuer
database.driver / dsn / postgres host 等
redis.host / port
session.cookie_name / secure / same_site / ttl
security.password_* / max_login_attempts / lockout_duration
oauth2.<provider>.*
social_auth_sync.enabled / interval / batch_size
smtp.*
secrets.client_secret_encryption_key
webauthn.rp_id / rp_origin / rp_display_name
admin.email / admin.password
```
常用文件:
- `configs/config.yaml`:默认主配置。
- `configs/config.sqlite.yaml`:SQLite 最小配置。
- `.env.example`:Docker Compose 环境变量模板。
- `docker-compose.yml`:PostgreSQL + Redis + App。
注意:`Dockerfile` 只构建 Go 服务并复制 `configs`、`db/migrations`。如果要容器内服务前端,需保证构建上下文里有可用的前端产物,或调整 Dockerfile 先构建 `frontend/dist`。
## 6. HTTP 路由总览
路由入口:`internal/router/router.go`。
### 公开路由
```text
GET /healthz
GET /readyz
GET /.well-known/openid-configuration
GET /jwks.json
```
### OIDC / OAuth2
```text
GET /oauth2/authorize
POST /oauth2/token
POST /oauth2/revoke
POST /oauth2/introspect
GET /oauth2/userinfo
POST /oauth2/userinfo
```
`/oauth2/authorize` 支持平台登录态检查、客户端准入检查、用户同意页挑战。
### API `/api/v1`
公开设置:
```text
GET /api/v1/settings/public
GET /api/v1/settings/password-policy
```
认证:
```text
POST /api/v1/auth/register/code
POST /api/v1/auth/register
POST /api/v1/auth/login
POST /api/v1/auth/logout
POST /api/v1/auth/verify-email
POST /api/v1/auth/forgot-password
POST /api/v1/auth/reset-password
POST /api/v1/auth/passkey/begin
POST /api/v1/auth/passkey/finish
```
社交登录/绑定:
```text
GET /api/v1/social/providers
GET /api/v1/social/{provider}/begin
GET /api/v1/social/{provider}/callback
```
登录用户:
```text
GET /api/v1/me
PUT /api/v1/me
PUT /api/v1/me/alias
PUT /api/v1/me/password
GET /api/v1/me/bindings
DELETE /api/v1/me/bindings/{provider}
GET /api/v1/me/security-level
POST /api/v1/me/resend-verification
GET /api/v1/me/sessions
DELETE /api/v1/me/sessions/{id}
GET /api/v1/me/authorized-apps
DELETE /api/v1/me/authorized-apps/{clientId}
```
用户 Passkey:
```text
POST /api/v1/me/passkeys/register/begin
POST /api/v1/me/passkeys/register/finish
GET /api/v1/me/passkeys
DELETE /api/v1/me/passkeys/{id}
PUT /api/v1/me/passkeys/{id}
```
OIDC 同意页:
```text
GET /api/v1/consent/context
POST /api/v1/consent/accept
POST /api/v1/consent/reject
```
开发者门户:
```text
GET /api/v1/developer/status
GET /api/v1/developer/apps
POST /api/v1/developer/apps
GET /api/v1/developer/apps/{id}
PUT /api/v1/developer/apps/{id}
DELETE /api/v1/developer/apps/{id}
POST /api/v1/developer/apps/{id}/rotate-secret
GET /api/v1/developer/apps/{id}/users
POST /api/v1/developer/apps/{id}/users/{user_id}/block
DELETE /api/v1/developer/apps/{id}/users/{user_id}/block
POST /api/v1/developer/apps/{id}/users/{user_id}/report
POST /api/v1/developer/apps/{id}/report-user
```
管理员:
```text
/api/v1/admin/users...
/api/v1/admin/clients...
/api/v1/admin/security-rules...
/api/v1/admin/providers...
/api/v1/admin/alias-restrictions...
/api/v1/admin/settings...
/api/v1/admin/audit-log
/api/v1/admin/stats
/api/v1/admin/keys...
/api/v1/admin/risk...
```
管理员路由都需要 session + `admin` 或 `super_admin`。
## 7. API 响应约定
定义在 `internal/handler/response.go`。
普通 API 响应统一包裹:
```json
{
"success": true,
"data": {},
"meta": {
"total": 100,
"offset": 0,
"limit": 20
}
}
```
错误:
```json
{
"success": false,
"error": {
"code": "invalid_input",
"message": "..."
}
}
```
例外:OIDC 标准端点和 `/oauth2/userinfo` 会按协议或 raw JSON 输出。
请求 JSON 解码使用 `DecodeJSON`,开启 `DisallowUnknownFields`,所以前端传多余字段会被拒绝。
用户身份字段边界:
- `id`:内部 UUID,供数据库外键、session、管理端操作路径、开发者应用用户封禁/举报等内部操作使用。
- `uid`:面向用户展示和搜索的纯数字 UID,不能替代内部主键。
- OIDC `sub` 默认仍使用内部 UUID,避免破坏已有客户端的用户关联。
- 前端显示“UID”时只展示 `uid`;需要调用操作接口时传 `id`。
## 8. 后端分层和模块边界
### 8.1 domain 层
路径:`internal/domain/`。
主要领域对象:
| 文件 | 作用 |
| --- | --- |
| `user.go` | 用户、社交绑定、绑定状态、授权检查状态 |
| `client.go` | OIDC 客户端、访问规则、开发者用户摘要 |
| `security_level.go` | 信任等级规则、条件类型、等级变更记录 |
| `provider.go` | Provider 枚举、Provider 配置、自定义 OAuth2 配置解析 |
| `session.go` | 平台用户 session |
| `risk.go` | 风控举报、风控名单、审计日志、签名密钥等 |
| `passkey.go` | Passkey/WebAuthn 凭据 |
领域层只放数据结构和轻量判断,不直接访问数据库或 HTTP。
### 8.2 port 层
路径:`internal/port/`。
作用是定义接口边界:
- `repository.go`:所有 repository interface。
- `cache.go`:缓存 interface。
- `email.go`:邮件发送 interface。
- `social_provider.go`:社交 Provider interface 和 Registry。
- `sms_provider.go`:短信能力边界。
新增业务能力时优先在 port 层加接口,再在 adapter 层实现。
### 8.3 adapter 层
路径:`internal/adapter/`。
| 子目录 | 作用 |
| --- | --- |
| `sqlite/` | SQLite repository、迁移、fosite store |
| `postgres/` | PostgreSQL repository、迁移、fosite store |
| `redis/` | Redis cache 实现 |
| `memcache/` | 内存 cache 实现 |
| `smtp/` | 邮件发送 |
| `social/` | GitHub/Google/Discord 等 Provider 适配 |
SQLite 和 PostgreSQL 的 repo 名称基本一一对应。修改持久化字段时通常要同步:
1. `db/migrations/*.sql`
2. `internal/domain/*.go`
3. `internal/port/repository.go`
4. `internal/adapter/sqlite/*_repo.go`
5. `internal/adapter/postgres/*_repo.go`
### 8.4 service 层
路径:`internal/service/`。
| 服务 | 责任 |
| --- | --- |
| `AuthService` | 注册、登录、登出、邮箱验证、找回密码、密码修改、登录锁定 |
| `SessionService` | session 创建、读取、撤销、cookie 生命周期相关辅助 |
| `SocialService` | 社交绑定、社交登录、Provider profile 保存、绑定状态同步 |
| `SecurityLevelService` | 信任等级规则评估、等级重算、等级详情和缺失条件 |
| `ClientService` | OIDC 客户端 CRUD、密钥加密/解密/轮换、配置校验 |
| `AccessControlService` | 客户端准入:最低等级、邮箱验证、邮箱/IP/用户 allow/deny、别名限制 |
| `AdminService` | 管理端聚合操作:用户、Provider、设置、签名密钥、Passkey 等 |
| `DeveloperHandler` 依赖的服务组合 | 开发者应用管理和用户举报入口 |
| `RiskService` | 滥用举报、管理员确认/驳回、风控名单、降级/封禁执行 |
| `PasskeyService` | WebAuthn 注册和登录仪式、凭据管理 |
| `SecretCipher` | OIDC client secret 加密 |
| `password_policy.go` / `password.go` | 密码策略和 Argon2id 哈希 |
服务层是业务规则核心。Handler 只做 HTTP 参数解析、响应映射和上下文提取。
### 8.5 handler 层
路径:`internal/handler/`。
| Handler | 作用 |
| --- | --- |
| `AuthHandler` | `/api/v1/auth/*` |
| `SocialHandler` | `/api/v1/social/*` |
| `UserInfoHandler` | `/api/v1/me/*` |
| `DeveloperHandler` | `/api/v1/developer/*` |
| `AdminHandler` | `/api/v1/admin/*` |
| `OIDCHandler` | `/oauth2/*` 和 consent API |
| `WellKnownHandler` | discovery 和 JWKS |
| `PasskeyHandler` | Passkey API |
| `HealthHandler` | 健康检查 |
| `SPAHandler` | 前端 SPA fallback |
中间件在 `internal/handler/middleware/`:
- session 鉴权、可选 session 鉴权。
- admin 权限检查。
- CORS。
- request id。
- logging。
- rate limit。
- Turnstile。
## 9. 核心数据模型和数据库表
主要表来自 `db/migrations/000001_initial.up.sql`,后续迁移补充风险、Provider 排序、Passkey 等。
核心表:
| 表 | 作用 |
| --- | --- |
| `users` | 平台用户,本地邮箱、密码哈希、角色、状态、信任等级 |
| `social_bindings` | 用户绑定的第三方账号,含 token、状态、`raw_profile` |
| `security_level_rules` | 信任等级规则,`conditions` 是 JSON |
| `security_level_changes` | 信任等级变更审计 |
| `oidc_clients` | 下游 OIDC 客户端 |
| `client_access_rules` | 客户端访问 allow/deny 规则 |
| `oauth2_authorization_codes` | fosite 授权码存储 |
| `oauth2_access_tokens` | fosite access token 存储 |
| `oauth2_refresh_tokens` | fosite refresh token 存储 |
| `oauth2_oidc_sessions` | OIDC session/consent 数据 |
| `oauth2_pkce_requests` | PKCE 请求存储 |
| `signing_keys` | OIDC 签名密钥 |
| `user_sessions` | 平台登录 session |
| `provider_configs` | 后台配置的 Provider |
| `global_settings` | 平台开关和全局设置 |
| `alias_restrictions` | 用户 alias 保留/禁用规则 |
| `audit_log` | 审计日志 |
| `risk_reports` | 开发者/管理员风控举报 |
| `risk_list` | 风控黑名单 |
| `passkey_credentials` | WebAuthn/Passkey 凭据 |
`social_bindings.raw_profile` 很关键:Provider 拉到的原始 profile 会被保存,信任等级规则可从这里读取字段。
## 10. 认证、登录和 OIDC 流程
### 10.1 本地邮箱密码登录
```mermaid
sequenceDiagram
participant FE as Frontend
participant H as AuthHandler
participant S as AuthService
participant R as User/Session Repo
FE->>H: POST /api/v1/auth/login
H->>S: Login(email,password,ip,userAgent)
S->>R: GetByEmail
S->>S: 验证密码、状态、登录锁定
S->>R: Create session + UpdateLastLogin
H-->>FE: Set-Cookie oidc_session
```
登录成功后前端 `auth.fetchUser()` 读取 `/api/v1/me`。
### 10.2 社交绑定
```mermaid
sequenceDiagram
participant FE as Frontend
participant SH as SocialHandler
participant SS as SocialService
participant P as Provider
participant DB as Binding Repo
FE->>SH: GET /api/v1/social/{provider}/begin (已登录)
SH->>SS: BeginBinding
SS->>SS: 写 OAuth state 到 cache
SS-->>FE: redirect provider auth URL
P-->>SH: callback code/state
SH->>SS: CompleteBinding
SS->>P: CompleteAuth 拉 profile
SS->>DB: Create social_binding(raw_profile)
SS->>SS: ComputeSecurityLevel
```
绑定后会重算信任等级。
### 10.3 社交登录
未登录状态访问 `/api/v1/social/{provider}/begin` 会进入 login 模式。callback 后如果 Provider UID 已绑定,则更新绑定 profile/token 并创建本平台 session;如果未绑定,可能按配置执行社交注册或返回错误。
### 10.4 OIDC 授权码流程
```mermaid
sequenceDiagram
participant App as Client App
participant O as OIDCHandler
participant U as User Session
participant C as ClientService
participant A as AccessControl
participant F as Fosite
App->>O: GET /oauth2/authorize
O->>F: NewAuthorizeRequest
O->>U: OptionalSessionAuth
O->>C: GetClientByClientID
O->>A: CheckAccess(client,user,ip)
O->>O: 创建 consent challenge
O-->>App: redirect /authorize?consent_challenge=...
App->>O: 用户同意后回到 authorize
O->>F: Grant scopes + NewAuthorizeResponse
F-->>App: authorization code
App->>O: POST /oauth2/token
O->>F: NewAccessRequest/NewAccessResponse
```
准入检查位置:`internal/handler/oidc_handler.go` + `internal/service/access_control_service.go`。
## 11. 信任等级规则系统
核心文件:
- `internal/domain/security_level.go`
- `internal/service/security_level_service.go`
- `frontend/src/pages/admin/security-rules.vue`
规则存储在 `security_level_rules.conditions` JSON 中,不改表结构即可扩展。
### 11.1 规则结构
```json
{
"operator": "AND",
"rules": [
{
"type": "provider_account_age_days",
"provider": "github",
"field": "created_at",
"operator": "gte",
"min_days": 180
}
]
}
```
旧规则仍兼容:
```json
{
"operator": "AND",
"rules": [
{
"provider": "github",
"min_binding_days": 30
}
]
}
```
旧规则会被解释为 `binding_age_days`。
### 11.2 条件类型
| type | 含义 | 主要字段 |
| --- | --- | --- |
| `provider_bound` | 已绑定某平台;provider 空表示任意活跃绑定 | `provider` |
| `binding_age_days` | 绑定时长 | `provider`, `operator`, `min_days` |
| `provider_account_age_days` | 第三方账号创建时长,如 GitHub `created_at` | `provider`, `field`, `operator`, `min_days` |
| `provider_email_verified` | Provider 明确返回邮箱验证状态 | `provider`, `operator`, `value` |
| `provider_email_domain` | Provider 邮箱域名 | `provider`, `values` |
| `provider_raw_number` | RawProfile 数字字段 | `provider`, `field`, `operator`, `value` |
| `provider_raw_string` | RawProfile 文本字段 | `provider`, `field`, `operator`, `value/values` |
| `provider_raw_bool` | RawProfile 布尔字段 | `provider`, `field`, `operator`, `value` |
| `user_email_domain` | 本地用户邮箱域名 | `values` |
| `user_created_age_days` | 本地用户注册天数 | `operator`, `min_days` |
| `user_has_verified_email` | 本地用户邮箱已验证 | `operator`, `value` |
比较方式:
- 数字:`gte`, `gt`, `lte`, `lt`, `eq`, `neq`,也兼容 `>=`, `>`, `<=`, `<`, `=`, `==`, `!=`。
- 字符串:`eq`, `neq`, `contains`, `prefix`, `suffix`, `regex`, `in`。
- 布尔:`eq`, `neq`。
### 11.3 评估原则
- `SecurityLevelService.ComputeSecurityLevel` 会读取用户、规则、绑定,然后从高等级到低等级排序匹配。
- 同等级按 `priority` 从高到低。
- 首个命中规则决定用户等级。
- 只使用 active binding;已解绑、禁用、过期等非活跃绑定不参与。
- `provider` 为空表示任意活跃绑定。
- `RawProfile` 路径支持点路径,如 `profile.company`。
- 时间支持 RFC3339Nano、RFC3339、`2006-01-02 15:04:05`、`2006-01-02` 和 unix timestamp。
- GitHub 账号注册天数必须来自 `RawProfile.created_at`,不能回退到绑定时间。
- 邮箱验证未知态不会被伪装成 false;条件不会匹配。
### 11.4 Provider RawProfile 标准化
文件:`internal/adapter/social/raw_profile.go`。
目标:在保留 Provider 原始字段的基础上,稳定派生通用字段:
- `email`
- `email_domain`
- `email_verified`:只有 Provider 明确提供可靠验证状态才写入。
各 Provider 的字段映射集中在 `internal/adapter/social/*.go`。
### 11.5 前端规则编辑器
页面:`frontend/src/pages/admin/security-rules.vue`。
支持:
- 新旧规则显示和编辑兼容。
- 条件类型选择。
- provider 推荐 + 可手填,支持 `custom_` / `oauth_` 自定义 Provider key。
- RawProfile 字段推荐 + 可手填路径。
- 数字、字符串、布尔、域名列表输入。
- GitHub 常用预设:`created_at`、`followers`、`following`、`public_repos`、`public_gists`。
文案:
- `frontend/src/i18n/zh.ts`
- `frontend/src/i18n/en.ts`
测试:
- `internal/service/security_level_service_test.go`
## 12. Provider 系统
核心接口:`internal/port/social_provider.go`。
Provider 需要实现:
```text
Name
BeginAuth
CompleteAuth
SupportsRefresh
RefreshToken
```
可选实现:`TokenValidatingProvider`,用于后续授权状态同步。
Registry:`internal/adapter/social/registry.go`。
Provider 来源:
1. 静态配置 `oauth2.<provider>`。
2. 数据库存储 `provider_configs`,由管理后台配置。
支持内置 Provider:
```text
github, google, gitlab, gitee, discord, telegram,
microsoft, apple, qq, wechat, phone
```
自定义 OAuth2 Provider:
- key 必须通过 `domain.IsValidCustomProviderKey`。
- key 需要以 `custom_` 或 `oauth_` 开头。
- 配置字段来自 `ProviderConfig.ExtraConfig`,例如授权端点、token 端点、userinfo 端点、字段路径等。
新增 Provider 的典型步骤:
1. 在 `internal/domain/provider.go` 增加常量和 `AllProviders`。
2. 在 `internal/adapter/social/` 增加 Provider 实现。
3. 在 `registry.go` 和 `cmd/server/bootstrap.go` 接入构造逻辑。
4. 在后台 Provider 页面和 i18n 增加展示字段。
5. 确认 `RawProfile` 字段标准化,不伪造不可证明字段。
## 13. 客户端和准入控制
客户端模型:`internal/domain/client.go`。
`OIDCClient` 关键字段:
- `ClientID`
- `ClientSecretEncrypted`
- `RedirectURIs`
- `GrantTypes`
- `ResponseTypes`
- `Scopes`
- `TokenEndpointAuthMethod`
- `MinSecurityLevel`
- `RequireEmailVerified`
- `IsConfidential`
- `IsActive`
- `OwnerUserID`
客户端服务:`internal/service/client_service.go`。
负责:
- 创建/更新客户端。
- 校验回调地址、grant type、scope、安全等级。
- 生成和加密 client secret。
- 轮换 secret。
- 验证 secret。
准入控制:`internal/service/access_control_service.go`。
检查顺序:
1. 客户端是否 active。
2. 用户状态是否 active。
3. 用户信任等级是否达到 `client.MinSecurityLevel`。
4. 客户端是否要求本地邮箱已验证。
5. `client_access_rules` 中的 user/email/email_domain/ip allow/deny。
注意:信任等级规则决定 `User.SecurityLevel`;客户端准入只消费这个等级并叠加自己的规则。
## 14. 风控系统
核心文件:
- `internal/domain/risk.go`
- `internal/service/risk_service.go`
- `frontend/src/pages/admin/risk.vue`
- `frontend/src/pages/developer/apps/[id]/users.vue`
流程:
```mermaid
flowchart LR
A[开发者举报用户] --> B[risk_reports pending]
B --> C{管理员确认?}
C -->|确认| D[用户降到 Lv0]
D --> E[用户状态 suspended]
E --> F[用户绑定账号进入 risk_list]
C -->|驳回| G[report dismissed]
```
`RiskService.ReportUser` 有自动升级逻辑:同一目标用户已有足够 confirmed reports 时,会自动确认当前报告并执行风控。
社交绑定/登录时会检查 `risk_list`,命中则阻止。
## 15. Passkey / WebAuthn
核心文件:
- `internal/domain/passkey.go`
- `internal/service/passkey_service.go`
- `internal/handler/passkey_handler.go`
- `db/migrations/000007_passkey_credentials.up.sql`
配置:
```text
webauthn.rp_id
webauthn.rp_origin
webauthn.rp_display_name
```
开关:`global_settings.passkey_enabled`。
登录和注册 challenge 存在 cache 中,key 前缀为 `passkey:challenge:`,过期时间 60 秒。
前端使用 `@simplewebauthn/browser`。
## 16. 前端结构
### 16.1 应用入口
- `frontend/src/main.ts`:创建 Vue app,挂载 Pinia、i18n、router。
- `frontend/src/App.vue`:只放 `RouterView` 和全局 Toast。
- `frontend/src/api/client.ts`:统一 API client。
- `frontend/src/stores/auth.ts`:登录态、用户信息、开发者权限。
### 16.2 路由
文件:`frontend/src/router/index.ts`。
主分组:
| 路径 | 布局 | 页面 |
| --- | --- | --- |
| `/` | `DefaultLayout` | 首页、features、docs、privacy、terms |
| `/login` 等 | `AuthLayout` | 登录、注册、找回密码、重置、授权确认、邮箱验证 |
| `/me` | `DashboardLayout` | 用户中心、会话、绑定、安全、授权应用 |
| `/developer` | `DeveloperLayout` | 开发者首页、创建应用、应用详情、应用用户 |
| `/admin` | `AdminLayout` | 管理首页、用户、客户端、规则、Provider、设置、审计、密钥、风控 |
路由守卫:
- 首次进入会并发 `auth.fetchUser()` 和 `auth.fetchPublicSettings()`。
- `requiresAuth` 未登录跳 `/login?return_to=...`。
- 登录用户访问受保护区域时拉取 developer status。
- `requiresAdmin` 检查 `role`。
- `requiresDeveloper` 检查 developer access。
### 16.3 API client
`frontend/src/api/client.ts`:
- base path 固定为 `/api/v1`。
- 每个请求默认 JSON。
- 默认带 cookie。
- 非 2xx 或 `success=false` 直接 throw `Error(message)`。
新增前端 API 通常不需要新 client,只需要页面内调用:
```ts
api.get<T>('/path')
api.post<T>('/path', body)
api.put<T>('/path', body)
api.del<T>('/path')
```
### 16.4 页面入口索引
用户端:
```text
frontend/src/pages/login.vue
frontend/src/pages/register.vue
frontend/src/pages/forgot-password.vue
frontend/src/pages/reset-password.vue
frontend/src/pages/verify-email.vue
frontend/src/pages/authorize.vue
frontend/src/pages/me/index.vue
frontend/src/pages/me/bindings.vue
frontend/src/pages/me/security.vue
frontend/src/pages/me/sessions.vue
frontend/src/pages/me/authorized.vue
```
开发者:
```text
frontend/src/pages/developer/index.vue
frontend/src/pages/developer/create.vue
frontend/src/pages/developer/apps/[id].vue
frontend/src/pages/developer/apps/[id]/users.vue
```
管理员:
```text
frontend/src/pages/admin/index.vue
frontend/src/pages/admin/users.vue
frontend/src/pages/admin/clients.vue
frontend/src/pages/admin/security-rules.vue
frontend/src/pages/admin/providers.vue
frontend/src/pages/admin/settings.vue
frontend/src/pages/admin/audit.vue
frontend/src/pages/admin/keys.vue
frontend/src/pages/admin/risk.vue
```
Provider 配置组件:
```text
frontend/src/components/admin/providers/*.vue
```
### 16.5 i18n
文件:
```text
frontend/src/i18n/index.ts
frontend/src/i18n/zh.ts
frontend/src/i18n/en.ts
```
页面新增文案必须同步中英文,否则构建期不一定报错,但运行时可能显示 key。
## 17. 数据流速查
### 17.1 本地用户注册
```mermaid
flowchart LR
A[注册页] --> B[SendRegisterCode]
B --> C[cache: register code]
C --> D[邮件发送]
A --> E[Register]
E --> F[校验 code/password/domain]
F --> G[users]
G --> H[audit_log]
```
### 17.2 社交绑定到信任等级
```mermaid
flowchart LR
A[Provider OAuth callback] --> B[ProviderUserInfo]
B --> C[SocialBinding.RawProfile]
C --> D[SecurityLevelService]
D --> E[security_level_rules.conditions]
E --> F[User.SecurityLevel]
F --> G[security_level_changes]
```
### 17.3 客户端授权
```mermaid
flowchart LR
A[下游 App authorize] --> B[OIDCHandler]
B --> C[本平台 session]
C --> D[ClientService]
D --> E[AccessControlService]
E --> F[Consent]
F --> G[Fosite authorization code]
G --> H[token + id_token]
```
### 17.4 风控举报
```mermaid
flowchart LR
A[Developer report] --> B[RiskService]
B --> C[risk_reports]
C --> D[Admin confirm]
D --> E[User suspended + Lv0]
E --> F[risk_list]
F --> G[后续社交登录/绑定拦截]
```
## 18. 常见修改入口
### 18.1 新增后端 API
1. 在合适的 service 加业务方法。
2. 在 handler 中加 HTTP 方法。
3. 在 `internal/router/router.go` 注册路由。
4. 如需持久化,先改 domain/port/repo/migration。
5. 前端页面调用 `api.*`。
6. 补 i18n 和测试。
### 18.2 新增数据库字段
1. 改 `db/migrations`。
2. 改 `internal/domain`。
3. 改 `internal/port/repository.go` 如果接口变化。
4. 同步 `internal/adapter/sqlite` 和 `internal/adapter/postgres`。
5. 检查 JSON 序列化字段名。
6. 跑 `go test ./...`。
### 18.3 新增信任等级条件
1. `internal/domain/security_level.go` 新增 condition type 和字段。
2. `internal/service/security_level_service.go`:
- `normalizeCondition`
- `validateCondition`
- `evaluateCondition`
- 必要时 `conditionStatus`
3. Provider 字段来自 `RawProfile` 时,优先在 `internal/adapter/social/raw_profile.go` 或具体 provider 适配器补标准化。
4. 前端 `frontend/src/pages/admin/security-rules.vue` 增加编辑能力。
5. 中英文 i18n 增加文案。
6. `internal/service/security_level_service_test.go` 补回归测试。
### 18.4 新增 Provider
参考“Provider 系统”章节。
重点不要把不可证明字段伪造成可证明字段。例如邮箱验证只能在 Provider 明确返回 verified/verified_email/email_verified 时写入。
### 18.5 改 OIDC token claims
相关文件:
- `internal/oidcprovider/session.go`
- `internal/oidcprovider/claims.go`
- `internal/handler/oidc_handler.go`
`Authorize` 中会调用 `oidcprovider.NewSession` 和 `oidcprovider.AddCustomClaims`。
需要保证 `/oauth2/userinfo` 和 ID Token claims 语义一致。
### 18.6 改前端权限导航
相关文件:
- `frontend/src/router/index.ts`
- `frontend/src/stores/auth.ts`
- 各 layout:`frontend/src/layouts/*.vue`
开发者权限由 `/api/v1/developer/status` 决定,不只是 `security_level` 单字段。
## 19. 测试和验证建议
必跑:
```bash
go test ./...
cd frontend && npm run build
```
按修改范围补充:
| 修改范围 | 重点验证 |
| --- | --- |
| 认证/注册/密码 | 登录、注册、找回、锁定、邮箱域名限制 |
| 社交 Provider | begin/callback、profile 保存、绑定冲突、risk list |
| 信任等级 | 旧规则兼容、AND/OR、RawProfile 字段缺失、非活跃绑定过滤 |
| OIDC | discovery、authorize、consent、token、userinfo、client secret |
| 客户端准入 | min level、email verified、email/ip/user allow/deny |
| Passkey | begin/finish register、begin/finish login、challenge 过期 |
| 前端页面 | vue-tsc 构建、i18n key、API 路径、权限守卫 |
## 20. 已知工程注意点
- 工作区可能存在未提交改动;不要随意回退用户或其他任务的变更。
- 后端 handler 的 JSON 解码拒绝未知字段,前端 payload 要精准。
- SQLite 和 PostgreSQL repository 经常要同步改。
- `security_level_rules.conditions` 是 JSON,扩展规则优先保持旧结构兼容。
- `social_bindings.raw_profile` 是信任等级高级规则的重要依据,Provider 修改要谨慎。
- 邮箱验证不能靠 `email != ""` 判断。
- GitHub 注册天数必须读 GitHub profile 的 `created_at`。
- `provider` 允许自定义 key,但必须满足 `custom_` 或 `oauth_` 前缀规则。
- 前端构建会跑 `vue-tsc -b`,模板里的 TypeScript 类型断言容易导致构建失败,复杂转换放到 script 方法里。
- `OIDC_OAUTH2_SECRET` 少于 32 字符时会随机生成,重启后 OAuth session 不可持续。
- 启动时会自动创建 signing key;JWKS 来自 `signing_keys` 表。
- 默认全局设置会在启动时 seed,包括注册、登录、社交绑定、Passkey 开关。
## 21. 当前仓库状态提示
最近完成的关键增强:
- 信任等级规则已从旧的 `provider + min_binding_days` 扩展为可读 Provider RawProfile 的通用规则系统。
- GitHub 注册天数读取 `RawProfile.created_at`。
- Provider 邮箱验证未知态不会匹配。
- 管理端规则 UI 已支持新结构并兼容旧规则。
- 新增 `internal/adapter/social/raw_profile.go`。
- 新增 `internal/service/security_level_service_test.go`。
如果后续 AI 接手信任等级相关问题,优先看:
```text
internal/domain/security_level.go
internal/service/security_level_service.go
internal/service/security_level_service_test.go
internal/adapter/social/raw_profile.go
internal/adapter/social/*.go
frontend/src/pages/admin/security-rules.vue
frontend/src/i18n/zh.ts
frontend/src/i18n/en.ts
```
## 22. 最短接手路径
如果你是新 AI,只需要按这个顺序读:
1. 本文档。
2. `internal/router/router.go` 看系统入口和 API 边界。
3. `cmd/server/bootstrap.go` 看依赖如何组装。
4. 当前任务相关的 service 文件。
5. 当前任务相关的 handler 文件。
6. 如涉及存储,再看对应 domain、port 和 repo。
7. 如涉及前端,再看 `frontend/src/router/index.ts`、`frontend/src/api/client.ts`、目标页面和 i18n。
不要一开始全仓库泛读,除非任务本身是架构重构。