基于 FastAPI 的共享账号管理系统,集成 Plug-in API 功能,支持传统用户名密码登录和 OAuth SSO 单点登录,提供完整的 AI 聊天服务和配额管理。
-
用户认证
- 传统用户名密码登录
- OAuth 2.0 SSO 单点登录(支持 Linux.do、GitHub)
- JWT 令牌认证
- 无感刷新机制(Refresh Token)
- 会话管理
- 令牌黑名单机制
- Token 轮换安全机制
-
用户管理
- 用户信息存储(PostgreSQL)
- OAuth 令牌管理
- 用户状态管理(激活/禁用/禁言)
- 信任等级系统
-
Plug-in API 集成
- 自动账号创建:用户注册时自动创建 Plug-in API 账号
- API 密钥安全存储:使用 Fernet 加密算法安全存储
- 代理请求:所有 Plug-in API 请求通过后端代理
- OpenAI 兼容接口:支持标准的 OpenAI API 格式
- 完整功能支持:账号管理、配额管理、聊天补全等
-
AI 聊天服务
- OpenAI 兼容的聊天补全 API
- 支持流式和非流式输出
- 多模型支持(Gemini 等)
- 智能 Cookie 选择和轮换
-
配额管理系统
- 用户共享配额池
- 自动配额恢复机制
- 配额消耗追踪和统计
- 专属/共享 Cookie 优先级设置
-
安全特性
- bcrypt 密码哈希(rounds=12)
- JWT Access Token (HS256, 默认24小时有效期)
- JWT Refresh Token (默认7天有效期)
- OAuth state 验证(防止 CSRF 攻击)
- Token 自动轮换机制
- API 密钥加密存储
-
缓存系统
- Redis 会话存储
- 令牌黑名单
- Refresh Token 存储和管理
- OAuth state 临时存储
- Web 框架: FastAPI 0.104+
- 数据库: PostgreSQL + SQLAlchemy 2.0 (异步)
- 缓存: Redis
- 认证: PyJWT + Passlib
- HTTP 客户端: httpx
- 数据库迁移: Alembic
- 数据验证: Pydantic
- Python 3.10+
- PostgreSQL 12+
- Redis 6+
- Plug-in API 服务(可选,用于 AI 聊天功能)
# 使用 uv
uv sync复制 .env.example 到 .env 并配置:
cp .env.example .env编辑 .env 文件,配置以下必需项:
# 应用配置
APP_ENV=development
LOG_LEVEL=INFO
# 数据库配置
DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/shared_accounts
# Redis 配置
REDIS_URL=redis://localhost:6379/0
# 或带密码: redis://:password@localhost:6379/0
# JWT 配置
JWT_SECRET_KEY=your-secret-key-change-this-in-production
JWT_ALGORITHM=HS256
JWT_EXPIRE_HOURS=24
# Refresh Token 配置
REFRESH_TOKEN_EXPIRE_DAYS=7
# REFRESH_TOKEN_SECRET_KEY=your-refresh-token-secret-key # 可选,默认使用 JWT_SECRET_KEY
# OAuth 配置(Linux.do)- 可选,如不配置则禁用该登录方式
LINUXDO_CLIENT_ID=your-linuxdo-client-id
LINUXDO_CLIENT_SECRET=your-linuxdo-client-secret
LINUXDO_REDIRECT_URI=http://localhost:8008/api/auth/sso/callback
# GitHub OAuth 配置 - 可选,如不配置则禁用该登录方式
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
GITHUB_REDIRECT_URI=http://localhost:3000/api/auth/github/callback
# Plug-in API 配置(可选)
PLUGIN_API_BASE_URL=http://localhost:8045
PLUGIN_API_ADMIN_KEY=sk-admin-your-admin-key-here
PLUGIN_API_ENCRYPTION_KEY=your-encryption-key-here-min-32-chars
# 账号创建配置
ALLOW_NEW_ACCOUNT_CREATION=true # 设置为 false 可禁止新用户注册
# PocketID OAuth 配置(可选)
# 自托管 OIDC 提供商,支持 Passkey 认证
# 仓库: https://github.com/pocket-id/pocket-id
POCKETID_BASE_URL=https://pocketid.example.com
POCKETID_CLIENT_ID=your-pocketid-client-id
POCKETID_CLIENT_SECRET=your-pocketid-client-secret
POCKETID_REDIRECT_URI=http://localhost:3000/auth/callback重要:PLUGIN_API_ENCRYPTION_KEY 必须是一个有效的 Fernet 密钥(32字节的URL安全base64编码)。可以使用以下 Python 代码生成:
from cryptography.fernet import Fernet
print(Fernet.generate_key().decode())# 运行数据库迁移
uv run alembic upgrade head# 使用启动脚本(推荐)
chmod +x run.sh
./run.sh
# 或直接使用 uvicorn
uv run uvicorn app.main:app --host 0.0.0.0 --port 8008 --reload
# 或使用 Python
uv run python app/main.py服务将在 http://localhost:8008 启动
启动服务后访问:
- Swagger UI: http://localhost:8008/api/docs
- ReDoc: http://localhost:8008/api/redoc
- OpenAPI JSON: http://localhost:8008/api/openapi.json
注意:生产环境中 API 文档将被禁用。
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/auth/login |
用户名密码登录 |
| POST | /api/auth/refresh |
刷新访问令牌(无感刷新) |
| GET | /api/auth/sso/initiate |
发起 OAuth SSO 登录 (已废弃,建议使用 OIDC 端点) |
| GET | /api/auth/sso/callback |
OAuth 回调处理 (已废弃,建议使用 OIDC 端点) |
| GET | /api/auth/github/login |
发起 GitHub OAuth 登录 (已废弃,建议使用 OIDC 端点) |
| POST | /api/auth/github/callback |
GitHub OAuth 回调处理 (已废弃,建议使用 OIDC 端点) |
| POST | /api/auth/logout |
用户登出 |
| POST | /api/auth/logout-all |
登出所有设备 |
| GET | /api/auth/me |
获取当前用户信息 |
| GET | /api/auth/check-username |
检查用户名是否存在 |
通用 OpenID Connect 认证端点,支持多种 OAuth 提供商:
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/auth/oidc/providers |
获取支持的 OIDC 提供商列表(含详细元数据) |
| GET | /api/auth/oidc/{provider}/login |
发起 OIDC 登录 (provider: linux_do, github, pocketid) |
| POST | /api/auth/oidc/{provider}/callback |
OIDC 回调处理 |
支持的提供商:
linux_do- Linux.do 社区认证github- GitHub OAuth 认证pocketid- 自托管 OIDC 提供商(支持 Passkey)
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/health |
系统健康状态检查 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/api-keys |
获取用户的 API 密钥列表 |
| POST | /api/api-keys |
创建新的 API 密钥 |
| DELETE | /api/api-keys/{key_id} |
删除指定的 API 密钥 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/plugin-api/accounts |
获取账号列表 |
| POST | /api/plugin-api/oauth/authorize |
获取 OAuth 授权 URL |
| GET | /api/plugin-api/quotas/user |
获取用户配额信息 |
| POST | /api/plugin-api/chat/completions |
聊天补全(OpenAI 兼容) |
| GET | /api/plugin-api/models |
获取可用模型列表 |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /v1/models |
获取模型列表 |
| POST | /v1/chat/completions |
聊天补全(流式/非流式) |
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/usage/stats |
获取使用统计信息 |
| GET | /api/usage/logs |
获取使用日志 |
系统实现了完整的无感刷新(Silent Refresh)机制,让用户无需频繁重新登录。
-
登录时:用户登录成功后,系统返回两个令牌:
access_token:短期有效(默认24小时),用于API请求认证refresh_token:长期有效(默认7天),用于刷新 access_token
-
API 请求:使用
access_token进行认证Authorization: Bearer <access_token> -
Token 刷新:当
access_token即将过期或已过期时,使用refresh_token获取新的令牌对POST /api/auth/refresh { "refresh_token": "<your_refresh_token>" } -
Token 轮换:每次刷新后,旧的
refresh_token失效,返回新的令牌对(安全机制)
// 示例:Axios 拦截器实现无感刷新
axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
// 如果是 401 错误且不是刷新请求本身
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// 使用 refresh_token 获取新令牌
const { data } = await axios.post('/api/auth/refresh', {
refresh_token: localStorage.getItem('refresh_token')
});
// 保存新令牌
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
// 重试原请求
originalRequest.headers.Authorization = `Bearer ${data.access_token}`;
return axios(originalRequest);
} catch (refreshError) {
// 刷新失败,需要重新登录
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 86400,
"user": {
"id": 1,
"username": "johndoe",
"avatar_url": "https://example.com/avatar.jpg",
"trust_level": 1,
"is_active": true,
"is_silenced": false
}
}{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 86400
}curl -X POST "http://localhost:8008/api/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "your_username",
"password": "your_password"
}'curl -X POST "http://localhost:8008/api/auth/refresh" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "YOUR_REFRESH_TOKEN"
}'注意:以下端点已废弃,请使用新的 OIDC 端点。
# 1. 获取授权 URL
curl "http://localhost:8008/api/auth/sso/initiate"
# 2. 用户在浏览器中访问返回的 authorization_url
# 3. 授权后会重定向到 callback URL 并自动完成登录注意:以下端点已废弃,请使用新的 OIDC 端点。
# 1. 获取 GitHub 授权 URL
curl "http://localhost:8008/api/auth/github/login"
# 2. 用户在浏览器中访问返回的 authorization_url
# 3. 授权后前端调用 callback 接口完成登录
curl -X POST "http://localhost:8008/api/auth/github/callback" \
-H "Content-Type: application/json" \
-d '{
"code": "github_authorization_code",
"state": "oauth_state"
}'使用新的通用 OIDC 端点,支持多种 OAuth 提供商:
# 1. 获取支持的提供商列表(含详细元数据)
curl "http://localhost:8008/api/auth/oidc/providers"
# 响应示例:
# {
# "providers": [
# {
# "id": "linux_do",
# "name": "Linux.do",
# "type": "linux_do",
# "enabled": true,
# "supports_refresh": true,
# "description": "Linux.do community authentication"
# },
# {
# "id": "github",
# "name": "GitHub",
# "type": "github",
# "enabled": true,
# "supports_refresh": true,
# "description": "GitHub OAuth authentication"
# },
# {
# "id": "pocketid",
# "name": "PocketID",
# "type": "pocketid",
# "enabled": true,
# "supports_refresh": true,
# "description": "Self-hosted OIDC with passkey support"
# }
# ]
# }
# 2. 使用 Linux.do 登录
curl "http://localhost:8008/api/auth/oidc/linux_do/login"
# 3. 使用 GitHub 登录
curl "http://localhost:8008/api/auth/oidc/github/login"
# 4. 使用 PocketID 登录
curl "http://localhost:8008/api/auth/oidc/pocketid/login"
# 5. 处理回调 (前端调用)
curl -X POST "http://localhost:8008/api/auth/oidc/{provider}/callback" \
-H "Content-Type: application/json" \
-d '{
"code": "authorization_code",
"state": "oauth_state"
}'前端集成详细指南: 完整的 React/TypeScript 实现示例请参考 FRONTEND_MIGRATION.md
curl "http://localhost:8008/api/auth/me" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"# 登出当前设备
curl -X POST "http://localhost:8008/api/auth/logout" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "YOUR_REFRESH_TOKEN"
}'
# 登出所有设备
curl -X POST "http://localhost:8008/api/auth/logout-all" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"curl -X POST "http://localhost:8008/api/api-keys" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "我的API密钥",
"description": "用于测试的密钥"
}'# 流式聊天
curl -X POST "http://localhost:8008/api/plugin-api/chat/completions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-high",
"messages": [
{"role": "user", "content": "你好,请介绍一下你自己"}
],
"stream": true
}'
# OpenAI 兼容格式
curl -X POST "http://localhost:8008/v1/chat/completions" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3-pro-high",
"messages": [
{"role": "user", "content": "你好,请介绍一下你自己"}
],
"stream": false
}'curl "http://localhost:8008/api/plugin-api/quotas/user" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"antigv-backend/
├── alembic/ # 数据库迁移脚本
│ ├── versions/ # 迁移版本文件
│ ├── env.py # Alembic 环境配置
│ └── script.py.mako # 迁移脚本模板
├── app/
│ ├── api/ # API 路由
│ │ ├── deps.py # 依赖注入
│ │ ├── deps_flexible.py # 灵活依赖注入
│ │ └── routes/ # 路由端点
│ │ ├── auth.py # 认证路由
│ │ ├── health.py # 健康检查
│ │ ├── plugin_api.py # Plug-in API 代理
│ │ ├── api_keys.py # API 密钥管理
│ │ ├── usage.py # 使用统计
│ │ └── v1.py # OpenAI 兼容接口
│ ├── cache/ # Redis 缓存
│ │ └── redis_client.py # Redis 客户端
│ ├── core/ # 核心模块
│ │ ├── config.py # 配置管理
│ │ ├── security.py # 安全功能
│ │ └── exceptions.py # 异常定义
│ ├── db/ # 数据库
│ │ ├── base.py # Base 类
│ │ └── session.py # 会话管理
│ ├── models/ # 数据模型
│ │ ├── user.py # 用户模型
│ │ ├── api_key.py # API 密钥模型
│ │ ├── oauth_token.py # OAuth 令牌模型
│ │ ├── plugin_api_key.py # Plug-in API 密钥模型
│ │ └── usage_log.py # 使用日志模型
│ ├── repositories/ # 数据仓储层
│ │ ├── user_repository.py # 用户仓储
│ │ ├── api_key_repository.py # API 密钥仓储
│ │ ├── oauth_token_repository.py # OAuth 令牌仓储
│ │ └── plugin_api_key_repository.py # Plug-in API 密钥仓储
│ ├── schemas/ # Pydantic Schemas
│ │ ├── user.py # 用户 Schema
│ │ ├── auth.py # 认证 Schema
│ │ ├── api_key.py # API 密钥 Schema
│ │ ├── token.py # 令牌 Schema
│ │ └── plugin_api.py # Plug-in API Schema
│ ├── services/ # 业务逻辑层
│ │ ├── auth_service.py # 认证服务
│ │ ├── user_service.py # 用户服务
│ │ ├── oauth_service.py # OAuth 服务
│ │ ├── github_oauth_service.py # GitHub OAuth 服务
│ │ └── plugin_api_service.py # Plug-in API 服务
│ ├── utils/ # 工具模块
│ │ └── encryption.py # 加密工具
│ └── main.py # 应用入口
├── .env.example # 环境变量示例
├── .gitignore # Git 忽略文件
├── .python-version # Python 版本
├── alembic.ini # Alembic 配置
├── pyproject.toml # 项目配置和依赖
├── uv.lock # uv 锁定文件
├── run.sh # 启动脚本
├── generate_encryption_key.py # 加密密钥生成工具
├── PLUGIN_API_INTEGRATION.md # Plug-in API 集成文档
├── plug-in-API.md # Plug-in API 使用文档
└── README.md # 项目文档
# 创建新的迁移
uv run alembic revision --autogenerate -m "描述信息"
# 应用迁移
uv run alembic upgrade head
# 回滚迁移
uv run alembic downgrade -1
# 查看迁移历史
uv run alembic history
# 查看当前版本
uv run alembic current项目使用类型注解和文档字符串,请保持一致的代码风格:
- 使用 Python 3.10+ 类型注解
- 所有公共函数和类都需要文档字符串
- 遵循 PEP 8 代码规范
- 使用异步编程模式(async/await)
APP_ENV=development
LOG_LEVEL=DEBUGAPP_ENV=production
LOG_LEVEL=INFO
# 确保使用强密码和安全的 JWT 密钥
# 建议为 Refresh Token 使用独立的密钥
# 配置适当的 CORS 源
# 禁用 API 文档如果要添加新的 Plug-in API 代理端点:
- 在
app/services/plugin_api_service.py中添加服务方法 - 在
app/api/routes/plugin_api.py中添加路由 - 在
app/schemas/plugin_api.py中添加相应的 Schema - 更新 API 文档
详细集成说明请参考 PLUGIN_API_INTEGRATION.md。
系统支持通过环境变量控制是否允许新用户通过 OAuth 注册账号。
在 .env 文件中设置:
# 允许新用户注册(默认)
ALLOW_NEW_ACCOUNT_CREATION=true
# 禁止新用户注册
ALLOW_NEW_ACCOUNT_CREATION=false- 启用时(true):新用户可以通过 OAuth(Linux.do 或 GitHub)登录并自动创建账号
- 禁用时(false):
- 已有用户可以正常登录
- 新用户尝试 OAuth 登录时会收到 403 错误:"新账号创建功能已关闭,请联系管理员"
- 适用于封闭测试、私有部署或维护期间
- 封闭 Beta 测试:仅允许特定用户访问
- 私有部署:企业内部使用,不对外开放
- 维护模式:暂时冻结新用户注册
- 容量控制:限制用户数量
# 运行测试(如果有的话)
uv run pytest
# 运行特定测试
uv run pytest tests/test_auth.pyFROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
EXPOSE 8008
CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8008"]# 安装依赖
uv sync
# 设置环境变量
export APP_ENV=production
# 运行数据库迁移
uv run alembic upgrade head
# 启动服务
uv run uvicorn app.main:app --host 0.0.0.0 --port 8008 --workers 4-
数据库连接失败
- 检查
DATABASE_URL配置 - 确保 PostgreSQL 服务正在运行
- 验证数据库用户权限
- 检查
-
Redis 连接失败
- 检查
REDIS_URL配置 - 确保 Redis 服务正在运行
- 验证 Redis 密码(如果有的话)
- 检查
-
OAuth 登录失败
- 检查 OAuth 客户端 ID 和密钥
- 验证回调 URL 配置
- 确保 OAuth 服务器可访问
-
Plug-in API 功能异常
- 检查
PLUGIN_API_BASE_URL配置 - 验证管理员密钥和加密密钥
- 确保 Plug-in API 服务正在运行
- 检查
-
Token 刷新失败
- 检查
refresh_token是否过期(默认7天) - 确认
refresh_token未被撤销 - 验证 Redis 服务正常运行
- 检查
# 查看应用日志
tail -f logs/app.log
# 查看特定级别日志
grep "ERROR" logs/app.logMIT License
欢迎提交 Issue 和 Pull Request!
- Fork 项目
- 创建功能分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
报告问题时请包含:
- 详细的问题描述
- 复现步骤
- 环境信息(操作系统、Python 版本等)
- 相关的错误日志