Ajout authentification JWT complète (app 100% protégée)

Backend:
- Nouveau module auth.py avec JWT et password handling
- Endpoint /api/auth/login (public)
- Endpoint /api/auth/me (protégé)
- TOUS les endpoints API protégés par require_auth
- Variables env: ADMIN_EMAIL, ADMIN_PASSWORD, JWT_SECRET_KEY
- Dependencies: python-jose, passlib

Frontend:
- Page de login (/login)
- AuthGuard component pour redirection automatique
- Axios interceptor: ajoute JWT token à chaque requête
- Gestion erreur 401: redirect automatique vers /login
- Bouton logout dans header
- Token stocké dans localStorage

Configuration:
- .env.example mis à jour avec variables auth
- Credentials admin configurables via env

Sécurité:
- Aucun endpoint public (sauf /api/auth/login et /health)
- JWT expiration configurable (24h par défaut)
- Password en clair dans env (à améliorer avec hash en prod)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-26 10:05:36 +01:00
parent 6ae861ff54
commit 774cb799a2
13 changed files with 522 additions and 11 deletions

View File

@@ -3,6 +3,7 @@
import { useState, useMemo } from "react"
import { useQuery } from "@tanstack/react-query"
import { getTracks, getApiUrl } from "@/lib/api"
import { logout, getUser } from "@/lib/auth"
import type { FilterParams, Track } from "@/lib/types"
import FilterPanel from "@/components/FilterPanel"
import AudioPlayer from "@/components/AudioPlayer"
@@ -160,6 +161,18 @@ export default function Home() {
{tracksData?.total || 0} piste{(tracksData?.total || 0) > 1 ? 's' : ''}
</div>
{/* Logout button */}
<button
onClick={logout}
className="px-3 py-2 text-sm text-slate-600 hover:text-slate-900 hover:bg-slate-100 rounded-lg transition-colors flex items-center gap-2"
title="Déconnexion"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
Logout
</button>
{/* Rescan button */}
<button
onClick={handleRescan}