- Nouveau membre créé avec email : un mot de passe temporaire aléatoire (~69 bits, sans caractères ambigus) est généré et haché ; il est retourné à l'admin et reste lisible en clair (users.temp_password) tant que le membre ne l'a pas changé - Colonnes users.temp_password / must_change_password (migration ALTER TABLE IF NOT EXISTS, appliquée au démarrage par le bootstrap) - POST /api/admin/members/:id/reset-access : régénère l'accès (création s'il n'existait pas, ou réinitialisation si le membre a perdu son mot de passe) ; login/me exposent mustChangePassword ; change-password efface systématiquement le mot de passe temporaire et lève le blocage - Frontend : colonne « Accès » dans la liste des membres (mot de passe visible + copier + réinitialiser, ou « Défini », ou « Créer l'accès »), modal de confirmation après création/réinitialisation, écran de changement de mot de passe obligatoire avant tout accès au portail ou au back-office Vérifié : cycle complet (création → mot de passe visible côté admin → connexion → changement forcé → effacement automatique → réinitialisation admin en cas de perte) via 21 tests e2e dédiés + parcours navigateur ; 34 tests existants toujours au vert. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fkg15RCxNgUys4ru73He2o
48 lines
1.2 KiB
React
48 lines
1.2 KiB
React
import { createContext, useContext, useEffect, useState } from 'react';
|
|
import { api } from './api.js';
|
|
|
|
const AuthContext = createContext(null);
|
|
|
|
export function AuthProvider({ children }) {
|
|
const [user, setUser] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
api
|
|
.get('/api/auth/me')
|
|
.then((d) => setUser(d.user))
|
|
.catch(() => setUser(null))
|
|
.finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
const login = async (email, password) => {
|
|
const d = await api.post('/api/auth/login', { email, password });
|
|
setUser(d.user);
|
|
return d.user;
|
|
};
|
|
|
|
const logout = async () => {
|
|
try {
|
|
await api.post('/api/auth/logout');
|
|
} finally {
|
|
setUser(null);
|
|
}
|
|
};
|
|
|
|
// Re-fetches the current user — used after a forced password change so
|
|
// mustChangePassword flips to false without a full re-login.
|
|
const refreshUser = async () => {
|
|
const d = await api.get('/api/auth/me');
|
|
setUser(d.user);
|
|
return d.user;
|
|
};
|
|
|
|
return (
|
|
<AuthContext.Provider value={{ user, loading, login, logout, refreshUser }}>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
}
|
|
|
|
export const useAuth = () => useContext(AuthContext);
|