Files
site11/services/oauth/backend/models.py
2025-09-28 20:41:57 +09:00

126 lines
5.7 KiB
Python

from beanie import Document, PydanticObjectId
from pydantic import BaseModel, Field, EmailStr
from typing import Optional, List, Dict
from datetime import datetime
from enum import Enum
class GrantType(str, Enum):
AUTHORIZATION_CODE = "authorization_code"
CLIENT_CREDENTIALS = "client_credentials"
PASSWORD = "password"
REFRESH_TOKEN = "refresh_token"
class ResponseType(str, Enum):
CODE = "code"
TOKEN = "token"
class TokenType(str, Enum):
BEARER = "Bearer"
class OAuthApplication(Document):
"""OAuth 2.0 클라이언트 애플리케이션"""
client_id: str = Field(..., unique=True, description="클라이언트 ID")
client_secret: str = Field(..., description="클라이언트 시크릿 (해시됨)")
name: str = Field(..., description="애플리케이션 이름")
description: Optional[str] = Field(None, description="애플리케이션 설명")
owner_id: str = Field(..., description="애플리케이션 소유자 ID")
redirect_uris: List[str] = Field(default_factory=list, description="허용된 리다이렉트 URI들")
allowed_scopes: List[str] = Field(default_factory=list, description="허용된 스코프들")
grant_types: List[GrantType] = Field(default_factory=lambda: [GrantType.AUTHORIZATION_CODE], description="허용된 grant types")
is_active: bool = Field(default=True, description="활성화 상태")
is_trusted: bool = Field(default=False, description="신뢰할 수 있는 앱 (자동 승인)")
# SSO 설정
sso_enabled: bool = Field(default=False, description="SSO 활성화 여부")
sso_provider: Optional[str] = Field(None, description="SSO 제공자 (google, github, saml 등)")
sso_config: Optional[Dict] = Field(default_factory=dict, description="SSO 설정 (provider별 설정)")
allowed_domains: List[str] = Field(default_factory=list, description="SSO 허용 도메인 (예: @company.com)")
website_url: Optional[str] = Field(None, description="애플리케이션 웹사이트")
logo_url: Optional[str] = Field(None, description="애플리케이션 로고 URL")
privacy_policy_url: Optional[str] = Field(None, description="개인정보 처리방침 URL")
terms_url: Optional[str] = Field(None, description="이용약관 URL")
created_at: datetime = Field(default_factory=datetime.now)
updated_at: datetime = Field(default_factory=datetime.now)
class Settings:
collection = "oauth_applications"
class AuthorizationCode(Document):
"""OAuth 2.0 인증 코드"""
code: str = Field(..., unique=True, description="인증 코드")
client_id: str = Field(..., description="클라이언트 ID")
user_id: str = Field(..., description="사용자 ID")
redirect_uri: str = Field(..., description="리다이렉트 URI")
scopes: List[str] = Field(default_factory=list, description="요청된 스코프")
code_challenge: Optional[str] = Field(None, description="PKCE code challenge")
code_challenge_method: Optional[str] = Field(None, description="PKCE challenge method")
expires_at: datetime = Field(..., description="만료 시간")
used: bool = Field(default=False, description="사용 여부")
used_at: Optional[datetime] = Field(None, description="사용 시간")
created_at: datetime = Field(default_factory=datetime.now)
class Settings:
collection = "authorization_codes"
class AccessToken(Document):
"""OAuth 2.0 액세스 토큰"""
token: str = Field(..., unique=True, description="액세스 토큰")
refresh_token: Optional[str] = Field(None, description="리프레시 토큰")
client_id: str = Field(..., description="클라이언트 ID")
user_id: Optional[str] = Field(None, description="사용자 ID (client credentials flow에서는 없음)")
token_type: TokenType = Field(default=TokenType.BEARER)
scopes: List[str] = Field(default_factory=list, description="부여된 스코프")
expires_at: datetime = Field(..., description="액세스 토큰 만료 시간")
refresh_expires_at: Optional[datetime] = Field(None, description="리프레시 토큰 만료 시간")
revoked: bool = Field(default=False, description="폐기 여부")
revoked_at: Optional[datetime] = Field(None, description="폐기 시간")
created_at: datetime = Field(default_factory=datetime.now)
last_used_at: Optional[datetime] = Field(None, description="마지막 사용 시간")
class Settings:
collection = "access_tokens"
class OAuthScope(Document):
"""OAuth 스코프 정의"""
name: str = Field(..., unique=True, description="스코프 이름 (예: read:profile)")
display_name: str = Field(..., description="표시 이름")
description: str = Field(..., description="스코프 설명")
is_default: bool = Field(default=False, description="기본 스코프 여부")
requires_approval: bool = Field(default=True, description="사용자 승인 필요 여부")
created_at: datetime = Field(default_factory=datetime.now)
class Settings:
collection = "oauth_scopes"
class UserConsent(Document):
"""사용자 동의 기록"""
user_id: str = Field(..., description="사용자 ID")
client_id: str = Field(..., description="클라이언트 ID")
granted_scopes: List[str] = Field(default_factory=list, description="승인된 스코프")
created_at: datetime = Field(default_factory=datetime.now)
updated_at: datetime = Field(default_factory=datetime.now)
expires_at: Optional[datetime] = Field(None, description="동의 만료 시간")
class Settings:
collection = "user_consents"
indexes = [
[("user_id", 1), ("client_id", 1)]
]