fix: исправлена проблема с обновлением refresh token (race condition)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 50s

- Добавлена синхронизация параллельных refresh-запросов
- Исправлена проблема сброса авторизации на следующий день
- Версия обновлена до 3.5.7
This commit is contained in:
poignatov
2026-01-10 18:38:15 +03:00
parent cbdcecea45
commit 3d3fa13f41
3 changed files with 27 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "play-life-web",
"version": "3.5.6",
"version": "3.5.7",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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 () => {