feat: Multi-User-Unterstützung mit JWT-Authentifizierung
- User-Modell (username, password_hash, role admin/user, is_active) - Standard-Admin-Benutzer wird beim ersten Start automatisch angelegt - JWT-Tokens (HS256) für Benutzer-Sessions, konfigurierbare Ablaufzeit - API-Key bleibt für service-to-service-Calls (backward-compatible) - POST /api/v1/auth/login → JWT-Token - GET /api/v1/auth/me → aktueller Benutzer - CRUD /api/v1/users/ → Benutzerverwaltung (nur Admin) - TUI zeigt Login-Screen beim Start; nach Erfolg → MainScreen - Passwort-Hashing mit bcrypt (python-jose für JWT)
This commit is contained in:
@@ -36,3 +36,27 @@ def get_db():
|
||||
def init_db() -> None:
|
||||
from db import models # noqa: F401 – Modelle müssen importiert sein
|
||||
Base.metadata.create_all(bind=engine)
|
||||
_create_default_admin()
|
||||
|
||||
|
||||
def _create_default_admin() -> None:
|
||||
"""Legt beim ersten Start einen Admin-Benutzer an, falls keine User existieren."""
|
||||
import bcrypt
|
||||
from db.models import User
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
if not db.query(User).first():
|
||||
pw_hash = bcrypt.hashpw(
|
||||
settings.default_admin_password.encode(), bcrypt.gensalt()
|
||||
).decode()
|
||||
admin = User(
|
||||
username=settings.default_admin_user,
|
||||
password_hash=pw_hash,
|
||||
role="admin",
|
||||
is_active=True,
|
||||
)
|
||||
db.add(admin)
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
17
db/models.py
17
db/models.py
@@ -23,6 +23,23 @@ def _uuid() -> str:
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
# ── User ───────────────────────────────────────────────────────────────────────
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id = Column(String(36), primary_key=True, default=_uuid)
|
||||
username = Column(String(64), nullable=False, unique=True, index=True)
|
||||
password_hash = Column(String(255), nullable=False)
|
||||
role = Column(
|
||||
Enum("admin", "user", name="user_role"),
|
||||
nullable=False,
|
||||
default="user",
|
||||
)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
created_at = Column(DateTime, default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
# ── Many-to-many: Conversation ↔ Contact ──────────────────────────────────────
|
||||
conversation_participants = Table(
|
||||
"conversation_participants",
|
||||
|
||||
Reference in New Issue
Block a user