From 3d3fa13f41f7e59c58552c224ce6ebcd2bf942be Mon Sep 17 00:00:00 2001 From: poignatov Date: Sat, 10 Jan 2026 18:38:15 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5?= =?UTF-8?q?=D0=BC=D0=B0=20=D1=81=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20refresh=20token=20(race=20cond?= =?UTF-8?q?ition)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлена синхронизация параллельных refresh-запросов - Исправлена проблема сброса авторизации на следующий день - Версия обновлена до 3.5.7 --- VERSION | 2 +- play-life-web/package.json | 2 +- .../src/components/auth/AuthContext.jsx | 27 +++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index c492825..3cf5751 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.5.6 +3.5.7 diff --git a/play-life-web/package.json b/play-life-web/package.json index 973fa67..37a9ba8 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "3.5.6", + "version": "3.5.7", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/components/auth/AuthContext.jsx b/play-life-web/src/components/auth/AuthContext.jsx index c1c847f..cd488e8 100644 --- a/play-life-web/src/components/auth/AuthContext.jsx +++ b/play-life-web/src/components/auth/AuthContext.jsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useState, useEffect, useCallback } from 'react' +import React, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react' const AuthContext = createContext(null) @@ -10,6 +10,9 @@ export function AuthProvider({ children }) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + + // Ref для синхронизации параллельных refresh-запросов + const refreshPromiseRef = useRef(null) const logout = useCallback(async () => { const token = localStorage.getItem(TOKEN_KEY) @@ -34,7 +37,8 @@ export function AuthProvider({ children }) { setUser(null) }, []) - const refreshToken = useCallback(async () => { + // Внутренняя функция для выполнения refresh + const doRefreshToken = useCallback(async () => { const refresh = localStorage.getItem(REFRESH_TOKEN_KEY) if (!refresh) { @@ -84,6 +88,25 @@ export function AuthProvider({ children }) { } }, []) + // Синхронизированная функция refresh - предотвращает race condition + // Если refresh уже выполняется, все вызовы ждут его завершения + const refreshToken = useCallback(async () => { + // Если refresh уже выполняется, ждём его завершения + if (refreshPromiseRef.current) { + console.log('[Auth] Refresh already in progress, waiting...') + return refreshPromiseRef.current + } + + // Создаём promise для refresh и сохраняем его + console.log('[Auth] Starting token refresh...') + refreshPromiseRef.current = doRefreshToken().finally(() => { + // Очищаем ref после завершения (успешного или нет) + refreshPromiseRef.current = null + }) + + return refreshPromiseRef.current + }, [doRefreshToken]) + // Initialize from localStorage useEffect(() => { const initAuth = async () => {