Files
AI/ontology_platform/ont_platform/auth/models.py

159 lines
4.4 KiB
Python
Raw Normal View History

"""인증 모델 (Organization, User, APIKey).
Phase 8: 멀티테넌트 지원
"""
from dataclasses import dataclass, field
from datetime import datetime, UTC
from typing import Optional, List
import uuid
@dataclass
class Organization:
"""조직 (테넌트)."""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
name: str = ""
created_at: datetime = field(default_factory=lambda: datetime.now(UTC))
updated_at: datetime = field(default_factory=lambda: datetime.now(UTC))
is_active: bool = True
subscription_tier: str = "free" # "free", "pro", "enterprise"
max_users: int = 5 # Free tier 기본값
storage_limit_gb: int = 1
api_quota_monthly: int = 10000
metadata: dict = field(default_factory=dict)
def to_dict(self) -> dict:
"""딕셔너리로 변환."""
return {
"id": self.id,
"name": self.name,
"created_at": self.created_at.isoformat(),
"is_active": self.is_active,
"subscription_tier": self.subscription_tier,
"max_users": self.max_users,
"storage_limit_gb": self.storage_limit_gb,
"api_quota_monthly": self.api_quota_monthly,
}
@dataclass
class User:
"""사용자."""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
org_id: str = "" # 조직 ID (FK)
email: str = ""
username: str = ""
hashed_password: str = ""
role: str = "viewer" # "admin", "editor", "viewer"
is_active: bool = True
created_at: datetime = field(default_factory=lambda: datetime.now(UTC))
updated_at: datetime = field(default_factory=lambda: datetime.now(UTC))
last_login: Optional[datetime] = None
metadata: dict = field(default_factory=dict)
def to_dict(self) -> dict:
"""딕셔너리로 변환."""
return {
"id": self.id,
"org_id": self.org_id,
"email": self.email,
"username": self.username,
"role": self.role,
"is_active": self.is_active,
"created_at": self.created_at.isoformat(),
"last_login": self.last_login.isoformat() if self.last_login else None,
}
@dataclass
class APIKey:
"""API 키."""
id: str = field(default_factory=lambda: str(uuid.uuid4()))
org_id: str = "" # 조직 ID (FK)
key_hash: str = "" # SHA256 해시 (원본은 저장하지 않음)
name: str = ""
description: str = ""
is_active: bool = True
created_at: datetime = field(default_factory=lambda: datetime.now(UTC))
last_used: Optional[datetime] = None
last_used_ip: Optional[str] = None
metadata: dict = field(default_factory=dict)
def to_dict(self) -> dict:
"""딕셔너리로 변환 (해시만 포함)."""
return {
"id": self.id,
"org_id": self.org_id,
"name": self.name,
"description": self.description,
"is_active": self.is_active,
"created_at": self.created_at.isoformat(),
"last_used": self.last_used.isoformat() if self.last_used else None,
}
@dataclass
class TokenPayload:
"""JWT 토큰 페이로드."""
user_id: str
org_id: str
email: str
role: str
exp: int # Unix timestamp
def to_dict(self) -> dict:
"""딕셔너리로 변환."""
return {
"user_id": self.user_id,
"org_id": self.org_id,
"email": self.email,
"role": self.role,
"exp": self.exp,
}
@dataclass
class AuthCredentials:
"""인증 자격증명."""
email: Optional[str] = None
password: Optional[str] = None
api_key: Optional[str] = None
token: Optional[str] = None
@dataclass
class CurrentUser:
"""현재 인증된 사용자."""
user_id: str
org_id: str
email: str
username: str
role: str
is_active: bool
def has_permission(self, action: str) -> bool:
"""사용자가 작업 권한을 가지고 있는지 확인."""
from ont_platform.auth.rbac import RBAC
rbac = RBAC()
permissions = rbac.get_permissions(self.role)
return action in permissions
def to_dict(self) -> dict:
"""딕셔너리로 변환."""
return {
"user_id": self.user_id,
"org_id": self.org_id,
"email": self.email,
"username": self.username,
"role": self.role,
"is_active": self.is_active,
}