Files
labs/oauth/backend/app/models/user.py
jungwoo choi 6c21809a24 feat: OAuth 2.0 백엔드 시스템 구현 완료
Phase 1 & 2 완료:
- 프로젝트 기본 구조 설정
- Docker Compose 환경 구성 (MongoDB, Redis, Backend, Frontend)
- FastAPI 기반 OAuth 2.0 백엔드 구현

주요 기능:
- JWT 기반 인증 시스템
- 3단계 권한 체계 (System Admin/Group Admin/User)
- 사용자 관리 CRUD API
- 애플리케이션 관리 CRUD API
- OAuth 2.0 Authorization Code Flow
- Refresh Token 관리
- 인증 히스토리 추적

API 엔드포인트:
- /auth/* - 인증 관련 (register, login, logout, refresh)
- /users/* - 사용자 관리
- /applications/* - 애플리케이션 관리
- /oauth/* - OAuth 2.0 플로우

보안 기능:
- bcrypt 비밀번호 해싱
- JWT 토큰 인증
- CORS 설정
- Rate limiting 준비

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-05 14:56:02 +09:00

108 lines
2.6 KiB
Python

"""User model definitions"""
from typing import Optional, List
from pydantic import BaseModel, EmailStr, Field, ConfigDict
from datetime import datetime
from enum import Enum
from bson import ObjectId
class UserRole(str, Enum):
"""User role enumeration"""
SYSTEM_ADMIN = "system_admin"
GROUP_ADMIN = "group_admin"
USER = "user"
class PyObjectId(ObjectId):
"""Custom ObjectId type for Pydantic"""
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if not ObjectId.is_valid(v):
raise ValueError("Invalid ObjectId")
return ObjectId(v)
@classmethod
def __get_pydantic_json_schema__(cls, field_schema):
field_schema.update(type="string")
class UserBase(BaseModel):
"""Base user model"""
email: EmailStr
username: str = Field(..., min_length=3, max_length=50)
full_name: Optional[str] = None
role: UserRole = UserRole.USER
profile_picture: Optional[str] = None
phone_number: Optional[str] = None
gender: Optional[str] = None
birth_date: Optional[str] = None
is_active: bool = True
model_config = ConfigDict(use_enum_values=True)
class UserCreate(UserBase):
"""User creation model"""
password: str = Field(..., min_length=8)
class UserUpdate(BaseModel):
"""User update model"""
email: Optional[EmailStr] = None
username: Optional[str] = Field(None, min_length=3, max_length=50)
full_name: Optional[str] = None
role: Optional[UserRole] = None
profile_picture: Optional[str] = None
phone_number: Optional[str] = None
gender: Optional[str] = None
birth_date: Optional[str] = None
is_active: Optional[bool] = None
password: Optional[str] = Field(None, min_length=8)
class User(UserBase):
"""User response model"""
id: str = Field(alias="_id")
created_at: datetime
updated_at: datetime
model_config = ConfigDict(
populate_by_name=True,
arbitrary_types_allowed=True,
json_encoders={ObjectId: str}
)
class UserInDB(User):
"""User model in database"""
hashed_password: str
class UserLogin(BaseModel):
"""User login model"""
username: str
password: str
class TokenData(BaseModel):
"""Token data model"""
user_id: Optional[str] = None
username: Optional[str] = None
role: Optional[str] = None
class Token(BaseModel):
"""Token response model"""
access_token: str
refresh_token: str
token_type: str = "bearer"
class TokenRefresh(BaseModel):
"""Token refresh request model"""
refresh_token: str