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:
@@ -24,12 +24,38 @@ export function getApiUrl(): string {
|
||||
|
||||
// Create axios instance dynamically to use runtime config
|
||||
function getApiClient() {
|
||||
return axios.create({
|
||||
const client = axios.create({
|
||||
baseURL: getApiUrl(),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
// Add JWT token to requests if available
|
||||
client.interceptors.request.use((config) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const token = localStorage.getItem('access_token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
// Handle 401 errors (redirect to login)
|
||||
client.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error.response?.status === 401 && typeof window !== 'undefined') {
|
||||
localStorage.removeItem('access_token')
|
||||
localStorage.removeItem('user')
|
||||
window.location.href = '/login'
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
// Tracks
|
||||
|
||||
34
frontend/lib/auth.ts
Normal file
34
frontend/lib/auth.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Authentication utilities
|
||||
*/
|
||||
|
||||
export function getToken(): string | null {
|
||||
if (typeof window === "undefined") return null
|
||||
return localStorage.getItem("access_token")
|
||||
}
|
||||
|
||||
export function setToken(token: string): void {
|
||||
localStorage.setItem("access_token", token)
|
||||
}
|
||||
|
||||
export function removeToken(): void {
|
||||
localStorage.removeItem("access_token")
|
||||
localStorage.removeItem("user")
|
||||
}
|
||||
|
||||
export function getUser(): any | null {
|
||||
if (typeof window === "undefined") return null
|
||||
const user = localStorage.getItem("user")
|
||||
return user ? JSON.parse(user) : null
|
||||
}
|
||||
|
||||
export function isAuthenticated(): boolean {
|
||||
return getToken() !== null
|
||||
}
|
||||
|
||||
export function logout(): void {
|
||||
removeToken()
|
||||
if (typeof window !== "undefined") {
|
||||
window.location.href = "/login"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user