fix: исправлена проблема с обновлением refresh token (race condition)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 50s
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:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "3.5.6",
|
"version": "3.5.7",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -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)
|
const AuthContext = createContext(null)
|
||||||
|
|
||||||
@@ -10,6 +10,9 @@ export function AuthProvider({ children }) {
|
|||||||
const [user, setUser] = useState(null)
|
const [user, setUser] = useState(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
|
|
||||||
|
// Ref для синхронизации параллельных refresh-запросов
|
||||||
|
const refreshPromiseRef = useRef(null)
|
||||||
|
|
||||||
const logout = useCallback(async () => {
|
const logout = useCallback(async () => {
|
||||||
const token = localStorage.getItem(TOKEN_KEY)
|
const token = localStorage.getItem(TOKEN_KEY)
|
||||||
@@ -34,7 +37,8 @@ export function AuthProvider({ children }) {
|
|||||||
setUser(null)
|
setUser(null)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const refreshToken = useCallback(async () => {
|
// Внутренняя функция для выполнения refresh
|
||||||
|
const doRefreshToken = useCallback(async () => {
|
||||||
const refresh = localStorage.getItem(REFRESH_TOKEN_KEY)
|
const refresh = localStorage.getItem(REFRESH_TOKEN_KEY)
|
||||||
|
|
||||||
if (!refresh) {
|
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
|
// Initialize from localStorage
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initAuth = async () => {
|
const initAuth = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user