sync: migrate secure-online-shop to Gitea (2026-08-10)
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.exceptions import ConflictError, UnauthorizedError
|
||||
from app.core.security import create_access_token, get_password_hash, verify_password
|
||||
from app.models.user import RoleEnum, User
|
||||
from app.schemas.auth import LoginRequest, UserCreate
|
||||
|
||||
audit_logger = logging.getLogger("app.audit")
|
||||
|
||||
|
||||
class AuthService:
|
||||
def __init__(self, db: Session) -> None:
|
||||
self.db = db
|
||||
|
||||
def register_user(self, payload: UserCreate) -> User:
|
||||
existing_user = self.db.scalar(select(User).where(User.username == payload.username))
|
||||
if existing_user is not None:
|
||||
raise ConflictError("Username already exists")
|
||||
|
||||
user = User(
|
||||
username=payload.username,
|
||||
password_hash=get_password_hash(payload.password),
|
||||
role=RoleEnum.client,
|
||||
is_active=True,
|
||||
)
|
||||
self.db.add(user)
|
||||
|
||||
try:
|
||||
self.db.commit()
|
||||
self.db.refresh(user)
|
||||
except IntegrityError as exc:
|
||||
self.db.rollback()
|
||||
raise ConflictError("Username already exists") from exc
|
||||
|
||||
audit_logger.info("user_registered user_id=%s role=%s", user.id, user.role.value)
|
||||
return user
|
||||
|
||||
def authenticate_user(self, payload: LoginRequest) -> str:
|
||||
user = self.db.scalar(select(User).where(User.username == payload.username))
|
||||
subject_hash = self._hash_subject(payload.username)
|
||||
|
||||
if user is None or not verify_password(payload.password, user.password_hash):
|
||||
audit_logger.warning("login_failed subject_hash=%s", subject_hash)
|
||||
raise UnauthorizedError("Invalid username or password")
|
||||
|
||||
if not user.is_active:
|
||||
audit_logger.warning("login_rejected_inactive user_id=%s", user.id)
|
||||
raise UnauthorizedError("Invalid username or password")
|
||||
|
||||
access_token = create_access_token(subject=str(user.id))
|
||||
audit_logger.info("login_success user_id=%s role=%s", user.id, user.role.value)
|
||||
return access_token
|
||||
|
||||
def get_user_by_id(self, user_id: int) -> User | None:
|
||||
return self.db.get(User, user_id)
|
||||
|
||||
@staticmethod
|
||||
def _hash_subject(subject: str) -> str:
|
||||
return hashlib.sha256(subject.encode("utf-8")).hexdigest()[:12]
|
||||
Reference in New Issue
Block a user