mirror of
https://github.com/furyhawk/agent_alpha.git
synced 2026-07-21 10:35:34 +00:00
- Introduced `auth_token_repo` for handling auth token operations in Redis. - Created `chat_repo` for managing chat sessions and messages in Redis. - Implemented `ChatService` and `AuthService` to encapsulate business logic for chat and authentication. - Updated routes to utilize new service and repository layers, removing direct database calls. - Enhanced user management with `UserService` for CRUD operations and user authentication. - Revised architecture documentation to reflect the new service-repository pattern.
73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
"""Authentication service — login, register, token management.
|
|
|
|
Usage::
|
|
|
|
service = AuthService(db, valkey)
|
|
token = await service.login("alice", "secret123")
|
|
user_id = await service.resolve_token(token)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
|
|
from redis.asyncio import Redis
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from backend.core.exceptions import NotFoundError
|
|
from backend.repositories import auth_token_repo, user_repo
|
|
from backend.services.user_service import UserService
|
|
|
|
|
|
class AuthService:
|
|
"""Service for authentication operations."""
|
|
|
|
def __init__(self, db: AsyncSession, valkey: Redis):
|
|
self.db = db
|
|
self.valkey = valkey
|
|
self._user_service = UserService(db)
|
|
|
|
async def register(
|
|
self,
|
|
*,
|
|
username: str,
|
|
display_name: str,
|
|
password: str,
|
|
role: str = "user",
|
|
team: str | None = None,
|
|
) -> tuple[object, str]:
|
|
"""Register a new user and return (user, token).
|
|
|
|
The first user to register is automatically assigned the ``admin`` role.
|
|
"""
|
|
total = await user_repo.count_all(self.db)
|
|
effective_role = "admin" if total == 0 else role
|
|
|
|
user = await user_repo.create_with_password(
|
|
self.db,
|
|
username=username,
|
|
display_name=display_name,
|
|
password=password,
|
|
role=effective_role,
|
|
team=team,
|
|
)
|
|
|
|
token = await auth_token_repo.create_token(self.valkey, str(user.id))
|
|
return user, token
|
|
|
|
async def login(self, username: str, password: str) -> tuple[object, str] | None:
|
|
"""Authenticate a user and return (user, token), or ``None`` on failure."""
|
|
user = await self._user_service.authenticate(username, password)
|
|
if user is None:
|
|
return None
|
|
token = await auth_token_repo.create_token(self.valkey, str(user.id))
|
|
return user, token
|
|
|
|
async def resolve_token(self, token: str) -> str | None:
|
|
"""Resolve a token to a user_id string, or ``None`` if invalid/expired."""
|
|
return await auth_token_repo.resolve_token(self.valkey, token)
|
|
|
|
async def logout(self, token: str) -> None:
|
|
"""Revoke an auth token."""
|
|
await auth_token_repo.revoke_token(self.valkey, token)
|