nice connexion + ooublications counter
This commit is contained in:
parent
4bf1370543
commit
044751c6d9
@ -149,7 +149,7 @@ from datetime import timedelta
|
|||||||
|
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
|
'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
|
||||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=36500),
|
||||||
'ROTATE_REFRESH_TOKENS': True,
|
'ROTATE_REFRESH_TOKENS': True,
|
||||||
'BLACKLIST_AFTER_ROTATION': True,
|
'BLACKLIST_AFTER_ROTATION': True,
|
||||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||||
|
|||||||
@ -22,11 +22,12 @@ function expireSession() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshAccessToken() {
|
export function refreshAccessToken() {
|
||||||
if (!refreshPromise) {
|
if (!refreshPromise) {
|
||||||
const refresh = localStorage.getItem('refresh');
|
const refresh = localStorage.getItem('refresh');
|
||||||
|
if (!refresh) return Promise.reject(new Error('Aucun jeton de renouvellement.'));
|
||||||
|
|
||||||
refreshPromise = refreshClient.post('/auth/refresh/', { refresh }).then(({ data }) => {
|
refreshPromise = refreshClient.post('/auth/refresh/', { refresh }).then(({ data }) => {
|
||||||
// Une déconnexion ou une nouvelle connexion peut avoir eu lieu pendant la requête.
|
|
||||||
if (localStorage.getItem('refresh') !== refresh) {
|
if (localStorage.getItem('refresh') !== refresh) {
|
||||||
throw new Error('La session a changé.');
|
throw new Error('La session a changé.');
|
||||||
}
|
}
|
||||||
@ -43,11 +44,19 @@ function refreshAccessToken() {
|
|||||||
return refreshPromise;
|
return refreshPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
api.interceptors.request.use((config) => {
|
api.interceptors.request.use(async (config) => {
|
||||||
const publicRequest = ['/auth/login/', '/users/register/'].includes(config.url);
|
const publicRequest = ['/auth/login/', '/users/register/'].includes(config.url);
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
config._publicRequest = publicRequest;
|
config._publicRequest = publicRequest;
|
||||||
if (token && !publicRequest) config.headers.Authorization = `Bearer ${token}`;
|
if (publicRequest) {
|
||||||
|
delete config.headers.Authorization;
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = localStorage.getItem('token');
|
||||||
|
if (!token && localStorage.getItem('refresh')) {
|
||||||
|
token = await refreshAccessToken();
|
||||||
|
}
|
||||||
|
if (token) config.headers.Authorization = `Bearer ${token}`;
|
||||||
else delete config.headers.Authorization;
|
else delete config.headers.Authorization;
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
@ -65,7 +74,6 @@ api.interceptors.response.use(
|
|||||||
request._retry = true;
|
request._retry = true;
|
||||||
const currentToken = localStorage.getItem('token');
|
const currentToken = localStorage.getItem('token');
|
||||||
const sentToken = request.headers.Authorization;
|
const sentToken = request.headers.Authorization;
|
||||||
// Une autre requête a peut-être déjà renouvelé la session.
|
|
||||||
const access = currentToken && sentToken !== `Bearer ${currentToken}`
|
const access = currentToken && sentToken !== `Bearer ${currentToken}`
|
||||||
? currentToken : await refreshAccessToken();
|
? currentToken : await refreshAccessToken();
|
||||||
request.headers.Authorization = `Bearer ${access}`;
|
request.headers.Authorization = `Bearer ${access}`;
|
||||||
|
|||||||
@ -14,26 +14,32 @@ export const AuthProvider = ({ children }) => {
|
|||||||
setIsAdmin(false);
|
setIsAdmin(false);
|
||||||
};
|
};
|
||||||
window.addEventListener('auth:logout', onLogout);
|
window.addEventListener('auth:logout', onLogout);
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
const token = localStorage.getItem('token');
|
if (localStorage.getItem('token') || localStorage.getItem('refresh')) {
|
||||||
|
|
||||||
if (token) {
|
|
||||||
try {
|
try {
|
||||||
// Verify token by fetching user profile
|
const { data: userData } = await api.get('/users/me/');
|
||||||
const response = await api.get('/users/me/');
|
if (!cancelled && (localStorage.getItem('token') || localStorage.getItem('refresh'))) {
|
||||||
const userData = response.data;
|
|
||||||
|
|
||||||
if (!cancelled && localStorage.getItem('token')) {
|
|
||||||
localStorage.setItem('user', JSON.stringify(userData));
|
localStorage.setItem('user', JSON.stringify(userData));
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
setIsAdmin(userData.is_admin || false);
|
setIsAdmin(Boolean(userData.is_admin));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to verify authentication', error);
|
console.error('Failed to verify authentication', error);
|
||||||
|
// Une panne réseau ne doit pas effacer la session conservée localement.
|
||||||
|
if (!cancelled && !error.response && localStorage.getItem('refresh')) {
|
||||||
|
try {
|
||||||
|
const cachedUser = JSON.parse(localStorage.getItem('user'));
|
||||||
|
if (cachedUser) {
|
||||||
|
setUser(cachedUser);
|
||||||
|
setIsAdmin(Boolean(cachedUser.is_admin));
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Le profil en cache est illisible : une prochaine requête pourra le récupérer.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cancelled) setLoading(false);
|
if (!cancelled) setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,52 +51,31 @@ export const AuthProvider = ({ children }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const login = async (username, password) => {
|
const login = async (username, password) => {
|
||||||
const response = await api.post('/auth/login/', {
|
const response = await api.post('/auth/login/', { username, password });
|
||||||
username,
|
|
||||||
password,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { access, refresh } = response.data;
|
const { access, refresh } = response.data;
|
||||||
|
|
||||||
localStorage.setItem('token', access);
|
localStorage.setItem('token', access);
|
||||||
localStorage.setItem('refresh', refresh);
|
localStorage.setItem('refresh', refresh);
|
||||||
|
|
||||||
// Fetch user info after login
|
const { data: userData } = await api.get('/users/me/');
|
||||||
const userResponse = await api.get('/users/me/');
|
|
||||||
const userData = userResponse.data;
|
|
||||||
|
|
||||||
localStorage.setItem('user', JSON.stringify(userData));
|
localStorage.setItem('user', JSON.stringify(userData));
|
||||||
|
|
||||||
setUser(userData);
|
setUser(userData);
|
||||||
setIsAdmin(userData.is_admin || false);
|
setIsAdmin(Boolean(userData.is_admin));
|
||||||
|
|
||||||
return userData;
|
return userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const register = async (data) => {
|
const register = async (data) => {
|
||||||
const response = await api.post('/users/register/', data);
|
const response = await api.post('/users/register/', data);
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
clearSession();
|
clearSession();
|
||||||
|
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setIsAdmin(false);
|
setIsAdmin(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider
|
<AuthContext.Provider value={{ user, login, register, logout, loading, isAdmin }}>
|
||||||
value={{
|
|
||||||
user,
|
|
||||||
login,
|
|
||||||
register,
|
|
||||||
logout,
|
|
||||||
loading,
|
|
||||||
isAdmin,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</AuthContext.Provider>
|
</AuthContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user