Backend Implementation (FastAPI + MongoDB): - JWT authentication with access/refresh tokens - User registration and login endpoints - Password hashing with bcrypt (fixed 72-byte limit) - Protected endpoints with JWT middleware - Token refresh mechanism - Role-Based Access Control (RBAC) structure - Pydantic v2 models and async MongoDB with Motor - API endpoints: /api/auth/register, /api/auth/login, /api/auth/me, /api/auth/refresh Frontend Implementation (React + TypeScript + Material-UI): - Login and Register pages with validation - AuthContext for global authentication state - API client with Axios interceptors for token refresh - Protected routes with automatic redirect - User profile display in navigation - Logout functionality Technical Achievements: - Resolved bcrypt 72-byte limit (replaced passlib with native bcrypt) - Fixed Pydantic v2 compatibility (PyObjectId, ConfigDict) - Implemented automatic token refresh on 401 errors - Created comprehensive test suite for all auth endpoints Docker & Kubernetes: - Backend image: yakenator/site11-console-backend:latest - Frontend image: yakenator/site11-console-frontend:latest - Deployed to site11-pipeline namespace - Nginx reverse proxy configuration Documentation: - CONSOLE_ARCHITECTURE.md - Complete system architecture - PHASE1_COMPLETION.md - Detailed completion report - PROGRESS.md - Updated with Phase 1 status All authentication endpoints tested and verified working. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
90 lines
2.6 KiB
Python
90 lines
2.6 KiB
Python
from pydantic import BaseModel, EmailStr, Field, ConfigDict
|
|
from typing import Optional
|
|
|
|
|
|
class UserRegister(BaseModel):
|
|
"""User registration schema"""
|
|
email: EmailStr = Field(..., description="User email")
|
|
username: str = Field(..., min_length=3, max_length=50, description="Username")
|
|
password: str = Field(..., min_length=6, description="Password")
|
|
full_name: Optional[str] = Field(None, description="Full name")
|
|
|
|
model_config = ConfigDict(
|
|
json_schema_extra={
|
|
"example": {
|
|
"email": "user@example.com",
|
|
"username": "johndoe",
|
|
"password": "securepassword123",
|
|
"full_name": "John Doe"
|
|
}
|
|
}
|
|
)
|
|
|
|
|
|
class UserLogin(BaseModel):
|
|
"""User login schema"""
|
|
username: str = Field(..., description="Username or email")
|
|
password: str = Field(..., description="Password")
|
|
|
|
model_config = ConfigDict(
|
|
json_schema_extra={
|
|
"example": {
|
|
"username": "johndoe",
|
|
"password": "securepassword123"
|
|
}
|
|
}
|
|
)
|
|
|
|
|
|
class Token(BaseModel):
|
|
"""Token response schema"""
|
|
access_token: str = Field(..., description="JWT access token")
|
|
refresh_token: Optional[str] = Field(None, description="JWT refresh token")
|
|
token_type: str = Field(default="bearer", description="Token type")
|
|
|
|
model_config = ConfigDict(
|
|
json_schema_extra={
|
|
"example": {
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"token_type": "bearer"
|
|
}
|
|
}
|
|
)
|
|
|
|
|
|
class TokenRefresh(BaseModel):
|
|
"""Token refresh schema"""
|
|
refresh_token: str = Field(..., description="Refresh token")
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
"""User response schema (without password)"""
|
|
id: str = Field(..., alias="_id", description="User ID")
|
|
email: EmailStr
|
|
username: str
|
|
full_name: Optional[str] = None
|
|
role: str
|
|
permissions: list = []
|
|
status: str
|
|
is_active: bool
|
|
created_at: str
|
|
last_login_at: Optional[str] = None
|
|
|
|
model_config = ConfigDict(
|
|
populate_by_name=True,
|
|
json_schema_extra={
|
|
"example": {
|
|
"_id": "507f1f77bcf86cd799439011",
|
|
"email": "user@example.com",
|
|
"username": "johndoe",
|
|
"full_name": "John Doe",
|
|
"role": "viewer",
|
|
"permissions": [],
|
|
"status": "active",
|
|
"is_active": True,
|
|
"created_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
}
|
|
)
|