Add foundational user authentication and registration system
Introduces schemas for user management, token handling, and password hashing. Implements routes for user registration, login, token refresh, and user info retrieval. Sets up authentication dependencies and integrates the API router with the application.
This commit is contained in:
0
backend/app/schemas/__init__.py
Normal file
0
backend/app/schemas/__init__.py
Normal file
54
backend/app/schemas/token.py
Normal file
54
backend/app/schemas/token.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class TokenBase(BaseModel):
|
||||
"""Base token schema with common attributes."""
|
||||
token_type: str = Field(default="bearer", description="Type of authentication token")
|
||||
expires_in: int = Field(description="Token expiration time in seconds")
|
||||
|
||||
|
||||
class Token(TokenBase):
|
||||
"""Schema for authentication response containing both access and refresh tokens."""
|
||||
access_token: str = Field(description="JWT access token")
|
||||
refresh_token: str = Field(description="JWT refresh token for obtaining new access tokens")
|
||||
|
||||
|
||||
class TokenPayload(BaseModel):
|
||||
"""Schema representing the decoded JWT token payload."""
|
||||
sub: str = Field(description="Subject identifier (user ID)")
|
||||
type: str = Field(description="Token type (access or refresh)")
|
||||
exp: datetime = Field(description="Token expiration timestamp")
|
||||
iat: datetime = Field(description="Token issued at timestamp")
|
||||
jti: Optional[str] = Field(None, description="JWT ID - unique identifier for the token")
|
||||
|
||||
|
||||
class RefreshToken(BaseModel):
|
||||
"""Schema for refresh token requests."""
|
||||
refresh_token: str = Field(
|
||||
...,
|
||||
description="JWT refresh token used to obtain new access tokens"
|
||||
)
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
"""Schema for detailed token information response."""
|
||||
access_token: str = Field(description="JWT access token")
|
||||
refresh_token: str = Field(description="JWT refresh token")
|
||||
token_type: str = Field(default="bearer")
|
||||
expires_in: int = Field(description="Token expiration time in seconds")
|
||||
scope: Optional[str] = Field(None, description="Token scope")
|
||||
user_id: str = Field(description="ID of the authenticated user")
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"token_type": "bearer",
|
||||
"expires_in": 1800,
|
||||
"scope": "read write",
|
||||
"user_id": "123e4567-e89b-12d3-a456-426614174000"
|
||||
}
|
||||
}
|
||||
66
backend/app/schemas/user.py
Normal file
66
backend/app/schemas/user.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from pydantic import BaseModel, EmailStr, Field, field_validator
|
||||
from datetime import datetime
|
||||
from passlib.hash import bcrypt
|
||||
|
||||
|
||||
# Base schema with shared user attributes
|
||||
class UserBase(BaseModel):
|
||||
"""Base schema with common user attributes."""
|
||||
email: EmailStr
|
||||
first_name: str
|
||||
last_name: str
|
||||
|
||||
|
||||
# Schema for creating a new user
|
||||
class UserCreate(UserBase):
|
||||
"""Schema for user registration."""
|
||||
password: str = Field(
|
||||
...,
|
||||
min_length=8,
|
||||
description="Password must be at least 8 characters"
|
||||
)
|
||||
|
||||
@field_validator('password')
|
||||
def password_strength(cls, v):
|
||||
# Add more complex password validation if needed
|
||||
if len(v) < 8:
|
||||
raise ValueError('Password must be at least 8 characters')
|
||||
return v
|
||||
|
||||
def hash_password(self) -> str:
|
||||
"""Hash the password before saving it to the database."""
|
||||
return bcrypt.hash(self.password)
|
||||
|
||||
|
||||
# Schema for updating user details
|
||||
class UserUpdate(BaseModel):
|
||||
"""Schema for updating user information."""
|
||||
email: Optional[EmailStr] = None
|
||||
first_name: Optional[str] = None
|
||||
last_name: Optional[str] = None
|
||||
phone_number: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
preferences: Optional[dict] = None # Provide preferences support
|
||||
|
||||
|
||||
# Schema for user responses (read-only fields)
|
||||
class UserResponse(UserBase):
|
||||
"""Schema for user responses in API."""
|
||||
id: UUID
|
||||
is_active: bool
|
||||
is_superuser: bool # Include roles or superuser flags if needed
|
||||
preferences: Optional[dict] = None # Include preferences in response
|
||||
created_at: datetime
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True # Enable mapping SQLAlchemy models to this schema
|
||||
|
||||
|
||||
# Schema for user authentication (e.g., login requests)
|
||||
class UserAuth(BaseModel):
|
||||
"""Schema for user authentication."""
|
||||
email: EmailStr
|
||||
password: str
|
||||
Reference in New Issue
Block a user