mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-13 12:55:19 +00:00
187 lines
5.8 KiB
Python
187 lines
5.8 KiB
Python
"""
|
||
用户私有模型凭据管理 - API 路由层
|
||
|
||
提供的接口:
|
||
- GET /api/v1/user/models - 获取当前用户的所有私有模型凭据
|
||
- POST /api/v1/user/models - 创建新的私有模型凭据
|
||
- PUT /api/v1/user/models/{id} - 更新指定的私有模型凭据
|
||
- DELETE /api/v1/user/models/{id} - 删除指定的私有模型凭据
|
||
|
||
安全设计:
|
||
- 所有接口都需要用户认证(get_verified_user)
|
||
- 返回数据时自动掩码 API Key(仅显示前 4 位和后 4 位)
|
||
- 更新/删除操作强制用户隔离(仅能操作自己的凭据)
|
||
"""
|
||
|
||
import logging
|
||
from typing import Optional
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException, status
|
||
|
||
from open_webui.constants import ERROR_MESSAGES
|
||
from open_webui.utils.auth import get_verified_user
|
||
from open_webui.models.user_model_credentials import (
|
||
UserModelCredentialForm,
|
||
UserModelCredentialResponse,
|
||
UserModelCredentials,
|
||
mask_api_key,
|
||
)
|
||
|
||
log = logging.getLogger(__name__)
|
||
|
||
router = APIRouter()
|
||
|
||
|
||
def _mask_response(model):
|
||
"""
|
||
响应数据掩码处理 - 保护 API Key 不被前端完整获取
|
||
|
||
转换流程:
|
||
1. 将内部模型(包含明文 api_key)转换为响应模型
|
||
2. 不回传明文 api_key,只返回掩码字段 api_key_masked
|
||
|
||
Args:
|
||
model: UserModelCredentialModel(包含明文 api_key)
|
||
|
||
Returns:
|
||
UserModelCredentialResponse: 掩码后的响应对象
|
||
"""
|
||
return UserModelCredentialResponse(
|
||
**{
|
||
**{
|
||
k: v
|
||
for k, v in model.model_dump().items()
|
||
if k not in ["api_key"]
|
||
},
|
||
"api_key_masked": mask_api_key(model.api_key), # 掩码 API Key
|
||
}
|
||
)
|
||
|
||
|
||
@router.get("", response_model=list[UserModelCredentialResponse])
|
||
async def list_user_credentials(user=Depends(get_verified_user)):
|
||
"""
|
||
获取当前用户的所有私有模型凭据
|
||
|
||
用途:前端模型选择器初始化时调用,获取用户保存的所有私有 API 配置
|
||
返回:掩码后的凭据列表(api_key_masked 字段,不暴露明文)
|
||
|
||
权限:仅返回当前用户的凭据
|
||
|
||
Returns:
|
||
list[UserModelCredentialResponse]: 用户的所有私有模型凭据列表
|
||
"""
|
||
# 查询当前用户的所有凭据
|
||
creds = UserModelCredentials.get_credentials_by_user_id(user.id)
|
||
# 掩码 API Key 后返回
|
||
return [_mask_response(c) for c in creds]
|
||
|
||
|
||
@router.post("", response_model=UserModelCredentialResponse)
|
||
async def create_user_credential(
|
||
form_data: UserModelCredentialForm, user=Depends(get_verified_user)
|
||
):
|
||
"""
|
||
创建新的私有模型凭据
|
||
|
||
用途:用户在前端添加自己的 LLM API(如自己的 OpenAI Key、Claude Key 等)
|
||
流程:
|
||
1. 接收前端提交的表单数据(model_id、base_url、api_key 等)
|
||
2. 自动关联当前用户 ID
|
||
3. 生成唯一凭据 ID
|
||
4. 保存到数据库
|
||
5. 返回掩码后的凭据对象
|
||
|
||
Args:
|
||
form_data: 前端提交的凭据表单(不包含 id 和 user_id)
|
||
user: 当前认证用户(由依赖注入自动获取)
|
||
|
||
Returns:
|
||
UserModelCredentialResponse: 创建成功的凭据对象(API Key 已掩码)
|
||
|
||
Raises:
|
||
HTTPException(400): 创建失败时抛出
|
||
"""
|
||
# 创建新凭据,自动关联当前用户 ID
|
||
cred = UserModelCredentials.insert_new_credential(user.id, form_data)
|
||
if not cred:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_400_BAD_REQUEST,
|
||
detail=ERROR_MESSAGES.DEFAULT(),
|
||
)
|
||
# 掩码 API Key 后返回
|
||
return _mask_response(cred)
|
||
|
||
|
||
@router.put("/{cred_id}", response_model=UserModelCredentialResponse)
|
||
async def update_user_credential(
|
||
cred_id: str, form_data: UserModelCredentialForm, user=Depends(get_verified_user)
|
||
):
|
||
"""
|
||
更新指定的私有模型凭据
|
||
|
||
用途:用户编辑自己保存的 API 凭据(修改 base_url、api_key、model_id 等)
|
||
安全校验:
|
||
- 凭据必须存在
|
||
- 凭据必须属于当前用户(user_id 匹配)
|
||
- 不满足条件返回 404
|
||
|
||
更新策略:仅更新前端提交的字段(部分更新)
|
||
|
||
Args:
|
||
cred_id: 凭据 ID(路径参数)
|
||
form_data: 更新的数据
|
||
user: 当前认证用户(由依赖注入自动获取)
|
||
|
||
Returns:
|
||
UserModelCredentialResponse: 更新后的凭据对象(API Key 已掩码)
|
||
|
||
Raises:
|
||
HTTPException(404): 凭据不存在或不属于当前用户
|
||
"""
|
||
# 更新凭据,自动校验用户权限
|
||
cred = UserModelCredentials.update_credential_by_id_and_user_id(
|
||
cred_id, user.id, form_data
|
||
)
|
||
if not cred:
|
||
# 凭据不存在或权限不足
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||
)
|
||
# 掩码 API Key 后返回
|
||
return _mask_response(cred)
|
||
|
||
|
||
@router.delete("/{cred_id}", response_model=bool)
|
||
async def delete_user_credential(cred_id: str, user=Depends(get_verified_user)):
|
||
"""
|
||
删除指定的私有模型凭据
|
||
|
||
用途:用户删除自己保存的 API 凭据
|
||
安全校验:
|
||
- 凭据必须存在
|
||
- 凭据必须属于当前用户(user_id 匹配)
|
||
- 不满足条件返回 404
|
||
|
||
Args:
|
||
cred_id: 凭据 ID(路径参数)
|
||
user: 当前认证用户(由依赖注入自动获取)
|
||
|
||
Returns:
|
||
bool: 删除成功返回 True
|
||
|
||
Raises:
|
||
HTTPException(404): 凭据不存在或不属于当前用户
|
||
"""
|
||
# 删除凭据,自动校验用户权限
|
||
result = UserModelCredentials.delete_credential_by_id_and_user_id(
|
||
cred_id, user.id
|
||
)
|
||
if not result:
|
||
# 凭据不存在或权限不足
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail=ERROR_MESSAGES.NOT_FOUND,
|
||
)
|
||
return True
|