Files
orion/models/schema/auth.py
Samir Boulahtit 6735d99df2 feat: implement customer authentication with JWT tokens
Implement secure customer authentication system with dedicated JWT tokens,
separate from admin/vendor authentication.

Backend Changes:
- Add customer JWT token support in deps.py
  - New get_current_customer_from_cookie_or_header dependency
  - Validates customer-specific tokens with type checking
  - Returns Customer object instead of User for shop routes
- Extend AuthService with customer token support
  - Add verify_password() method
  - Add create_access_token_with_data() for custom token payloads
- Update CustomerService authentication
  - Generate customer-specific JWT tokens with type="customer"
  - Use vendor-scoped customer lookup
- Enhance exception handler
  - Sanitize validation errors to prevent password leaks in logs
  - Fix shop login redirect to support multi-access routing
- Improve vendor context detection from Referer header
  - Consistent "path" detection method for cookie path logic

Schema Changes:
- Rename UserLogin.username to email_or_username for flexibility
- Update field validators accordingly

API Changes:
- Update admin/vendor auth endpoints to use email_or_username
- Customer auth already uses email field correctly

Route Changes:
- Update shop account routes to use Customer dependency
- Add /account redirect (without trailing slash)
- Change parameter names from current_user to current_customer

Frontend Changes:
- Update login forms to use email_or_username in API calls
- Change button text from "Log in" to "Sign in" for consistency
- Improve loading spinner layout with flexbox

Security Improvements:
- Customer tokens scoped to vendor_id
- Token type validation prevents cross-context token usage
- Password inputs redacted from validation error logs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:08:49 +01:00

59 lines
1.7 KiB
Python

# auth.py - Keep security-critical validation
import re
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
class UserRegister(BaseModel):
email: EmailStr = Field(..., description="Valid email address")
username: str = Field(..., description="Username")
password: str = Field(..., description="Password")
# Keep security validation in Pydantic for auth
@field_validator("username")
@classmethod
def validate_username(cls, v):
if not re.match(r"^[a-zA-Z0-9_]+$", v):
raise ValueError("Username must contain only letters, numbers, or underscores")
return v.lower().strip()
@field_validator("password")
@classmethod
def validate_password(cls, v):
if len(v) < 6:
raise ValueError("Password must be at least 6 characters long")
return v
class UserLogin(BaseModel):
email_or_username: str = Field(..., description="Username or email address")
password: str = Field(..., description="Password")
vendor_code: Optional[str] = Field(None, description="Optional vendor code for context")
@field_validator("email_or_username")
@classmethod
def validate_email_or_username(cls, v):
return v.strip()
class UserResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
email: str
username: str
role: str
is_active: bool
last_login: Optional[datetime] = None
created_at: datetime
updated_at: datetime
class LoginResponse(BaseModel):
access_token: str
token_type: str = "bearer"
expires_in: int
user: UserResponse