freeleaps-ops/apps/gitea-webhook-ambassador-python/app/handlers/auth.py
Nicolas f6c515157c feat: 添加 Python 版本的 Gitea Webhook Ambassador
- 新增完整的 Python 实现,替代 Go 版本
- 添加 Web 登录界面和仪表板
- 实现 JWT 认证和 API 密钥管理
- 添加数据库存储功能
- 保持与 Go 版本一致的目录结构和启动脚本
- 包含完整的文档和测试脚本
2025-07-20 21:17:10 +08:00

122 lines
3.1 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPBearer
from sqlalchemy.orm import Session
from pydantic import BaseModel
from typing import List, Optional
import os
from ..models.database import get_db, APIKey
from ..auth.middleware import auth_middleware
router = APIRouter(prefix="/api/auth", tags=["authentication"])
# 请求/响应模型
class LoginRequest(BaseModel):
secret_key: str
class LoginResponse(BaseModel):
token: str
class APIKeyCreate(BaseModel):
description: str
class APIKeyResponse(BaseModel):
id: int
key: str
description: Optional[str]
created_at: str
class Config:
from_attributes = True
class APIKeyList(BaseModel):
keys: List[APIKeyResponse]
# 获取管理员密钥
def get_admin_secret_key():
return os.getenv("ADMIN_SECRET_KEY", "admin-secret-key-change-in-production")
@router.post("/login", response_model=LoginResponse)
async def login(request: LoginRequest):
"""管理员登录"""
admin_key = get_admin_secret_key()
if request.secret_key != admin_key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid secret key"
)
# 生成 JWT 令牌
token = auth_middleware.create_access_token(
data={"sub": "admin", "role": "admin"}
)
return LoginResponse(token=token)
@router.post("/keys", response_model=APIKeyResponse)
async def create_api_key(
request: APIKeyCreate,
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""创建新的 API 密钥"""
# 生成新的 API 密钥
api_key_value = auth_middleware.generate_api_key()
# 保存到数据库
db_key = APIKey(
key=api_key_value,
description=request.description
)
db.add(db_key)
db.commit()
db.refresh(db_key)
return APIKeyResponse(
id=db_key.id,
key=db_key.key,
description=db_key.description,
created_at=db_key.created_at.isoformat()
)
@router.get("/keys", response_model=APIKeyList)
async def list_api_keys(
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""获取所有 API 密钥"""
keys = db.query(APIKey).order_by(APIKey.created_at.desc()).all()
return APIKeyList(
keys=[
APIKeyResponse(
id=key.id,
key=key.key,
description=key.description,
created_at=key.created_at.isoformat()
)
for key in keys
]
)
@router.delete("/keys/{key_id}")
async def delete_api_key(
key_id: int,
db: Session = Depends(get_db),
current_user: dict = Depends(auth_middleware.get_current_user)
):
"""删除 API 密钥"""
key = db.query(APIKey).filter(APIKey.id == key_id).first()
if not key:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="API key not found"
)
db.delete(key)
db.commit()
return {"message": "API key deleted successfully"}