Files
aiagent/backend/app/models/api_key.py

63 lines
2.3 KiB
Python
Raw Normal View History

"""
API Key 模型 用于第三方应用/脚本通过 API 调用平台服务
"""
import hashlib
import logging
from datetime import datetime
from typing import Optional
from sqlalchemy import Column, String, DateTime, JSON, func, ForeignKey
from sqlalchemy.dialects.mysql import CHAR
from sqlalchemy.orm import relationship, Session
from app.core.database import Base
import uuid
logger = logging.getLogger(__name__)
KEY_PREFIX = "sk-tg-"
class ApiKey(Base):
"""API Key 表"""
__tablename__ = "api_keys"
id = Column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()), comment="密钥ID")
user_id = Column(CHAR(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, comment="所属用户ID")
workspace_id = Column(CHAR(36), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, comment="所属工作区ID")
name = Column(String(100), nullable=False, comment="密钥名称(用于标识)")
key_prefix = Column(String(12), nullable=False, comment="密钥前缀(如 sk-tg-")
key_hash = Column(String(255), nullable=False, unique=True, comment="SHA256 哈希存储")
permissions = Column(JSON, nullable=True, comment="权限范围null=全部权限)")
last_used_at = Column(DateTime, nullable=True, comment="最后使用时间")
expires_at = Column(DateTime, nullable=True, comment="过期时间null=永不过期)")
status = Column(String(20), default="active", comment="状态: active/revoked")
created_at = Column(DateTime, default=func.now(), comment="创建时间")
# 关系
user = relationship("User", backref="api_keys")
def __repr__(self):
return f"<ApiKey(id={self.id}, name={self.name}, status={self.status})>"
def verify_api_key(api_key_str: str, db: Session) -> Optional["ApiKey"]:
"""验证 API Key 字符串,返回 ApiKey 对象或 None。"""
if not api_key_str or not api_key_str.startswith(KEY_PREFIX):
return None
key_hash = hashlib.sha256(api_key_str.encode()).hexdigest()
api_key = db.query(ApiKey).filter(
ApiKey.key_hash == key_hash,
ApiKey.status == "active",
).first()
if not api_key:
return None
if api_key.expires_at and api_key.expires_at < datetime.utcnow():
logger.warning("API Key %s 已过期", api_key.id)
return None
return api_key