From 99814b57d97e231640a32c0f0a7ed14539142224 Mon Sep 17 00:00:00 2001 From: yangdx Date: Wed, 19 Mar 2025 19:08:09 +0800 Subject: [PATCH] Refactor navigation and authentication flow - Move navigation setup to AppRouter - Prevent protected route logic to handle login 401 --- lightrag_webui/src/App.tsx | 13 +---- lightrag_webui/src/AppRouter.tsx | 64 ++++++++++++++--------- lightrag_webui/src/api/lightrag.ts | 7 ++- lightrag_webui/src/features/LoginPage.tsx | 10 +++- lightrag_webui/src/services/navigation.ts | 27 +++++++--- 5 files changed, 75 insertions(+), 46 deletions(-) diff --git a/lightrag_webui/src/App.tsx b/lightrag_webui/src/App.tsx index e6155c14..4596f684 100644 --- a/lightrag_webui/src/App.tsx +++ b/lightrag_webui/src/App.tsx @@ -5,11 +5,9 @@ import MessageAlert from '@/components/MessageAlert' import ApiKeyAlert from '@/components/ApiKeyAlert' import StatusIndicator from '@/components/graph/StatusIndicator' import { healthCheckInterval } from '@/lib/constants' -import { useBackendState, useAuthStore } from '@/stores/state' +import { useBackendState } from '@/stores/state' import { useSettingsStore } from '@/stores/settings' import { useEffect } from 'react' -import { useNavigate } from 'react-router-dom' -import { navigationService } from '@/services/navigation' import SiteHeader from '@/features/SiteHeader' import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag' @@ -21,22 +19,13 @@ import ApiSite from '@/features/ApiSite' import { Tabs, TabsContent } from '@/components/ui/Tabs' function App() { - const navigate = useNavigate(); const message = useBackendState.use.message() - - // Initialize navigation service - useEffect(() => { - navigationService.setNavigate(navigate); - }, [navigate]); const enableHealthCheck = useSettingsStore.use.enableHealthCheck() const currentTab = useSettingsStore.use.currentTab() const [apiKeyInvalid, setApiKeyInvalid] = useState(false) // Health check useEffect(() => { - const { isAuthenticated } = useAuthStore.getState(); - if (!enableHealthCheck || !isAuthenticated) return - // Check immediately useBackendState.getState().check() diff --git a/lightrag_webui/src/AppRouter.tsx b/lightrag_webui/src/AppRouter.tsx index 5fafd43f..a0857f67 100644 --- a/lightrag_webui/src/AppRouter.tsx +++ b/lightrag_webui/src/AppRouter.tsx @@ -1,4 +1,4 @@ -import { HashRouter as Router, Routes, Route, Navigate } from 'react-router-dom' +import { HashRouter as Router, Routes, Route, useNavigate } from 'react-router-dom' import { useEffect, useState } from 'react' import { useAuthStore } from '@/stores/state' import { navigationService } from '@/services/navigation' @@ -16,6 +16,12 @@ interface ProtectedRouteProps { const ProtectedRoute = ({ children }: ProtectedRouteProps) => { const { isAuthenticated } = useAuthStore() const [isChecking, setIsChecking] = useState(true) + const navigate = useNavigate() + + // Set navigate function for navigation service + useEffect(() => { + navigationService.setNavigate(navigate) + }, [navigate]) useEffect(() => { let isMounted = true; // Flag to prevent state updates after unmount @@ -71,29 +77,33 @@ const ProtectedRoute = ({ children }: ProtectedRouteProps) => { // Get current path and check if it's a direct access const currentPath = window.location.hash.slice(1); // Remove the '#' from hash const isLoginPage = currentPath === '/login'; - const isDirectAccess = !document.referrer; - - // Handle direct access to root path - if (isDirectAccess && currentPath === '/') { - navigationService.resetAllApplicationState(); - } - + // Skip redirect if already on login page if (isLoginPage) { return null; } - // Use React Router's Navigate for redirection - console.log('Not authenticated, redirecting to login'); - return ; + // For non-login pages, handle state reset and navigation + if (!isLoginPage) { + // Use navigation service for redirection + console.log('Not authenticated, redirecting to login'); + navigationService.navigateToLogin(); + return null; + } } return <>{children} } -const AppRouter = () => { +const AppContent = () => { const [initializing, setInitializing] = useState(true) const { isAuthenticated } = useAuthStore() + const navigate = useNavigate() + + // Set navigate function for navigation service + useEffect(() => { + navigationService.setNavigate(navigate) + }, [navigate]) // Check token validity and auth configuration on app initialization useEffect(() => { @@ -152,21 +162,27 @@ const AppRouter = () => { return null } + return ( + + } /> + + + + } + /> + + ) +} + +const AppRouter = () => { return ( - - } /> - - - - } - /> - - + + ) diff --git a/lightrag_webui/src/api/lightrag.ts b/lightrag_webui/src/api/lightrag.ts index fcccf9bd..0406075a 100644 --- a/lightrag_webui/src/api/lightrag.ts +++ b/lightrag_webui/src/api/lightrag.ts @@ -173,9 +173,12 @@ axiosInstance.interceptors.response.use( (error: AxiosError) => { if (error.response) { if (error.response?.status === 401) { - // Use navigation service to handle redirection + // For login API, throw error directly + if (error.config?.url?.includes('/login')) { + throw error; + } + // For other APIs, navigate to login page navigationService.navigateToLogin(); - // Return a never-resolving promise to prevent further execution return new Promise(() => {}); } diff --git a/lightrag_webui/src/features/LoginPage.tsx b/lightrag_webui/src/features/LoginPage.tsx index 16cff851..bc00b5c9 100644 --- a/lightrag_webui/src/features/LoginPage.tsx +++ b/lightrag_webui/src/features/LoginPage.tsx @@ -48,7 +48,7 @@ const LoginPage = () => { toast.info(status.message) } navigate('/') - return; // Exit early, no need to set checkingAuth to false + return // Exit early, no need to set checkingAuth to false } } catch (error) { console.error('Failed to check auth configuration:', error) @@ -95,11 +95,17 @@ const LoginPage = () => { } else { toast.success(t('login.successMessage')) } - + + // Navigate to home page after successful login navigate('/') } catch (error) { console.error('Login failed...', error) toast.error(t('login.errorInvalidCredentials')) + + // Clear any existing auth state + useAuthStore.getState().logout() + // Clear local storage + localStorage.removeItem('LIGHTRAG-API-TOKEN') } finally { setLoading(false) } diff --git a/lightrag_webui/src/services/navigation.ts b/lightrag_webui/src/services/navigation.ts index cc5651bb..12019a0e 100644 --- a/lightrag_webui/src/services/navigation.ts +++ b/lightrag_webui/src/services/navigation.ts @@ -61,13 +61,28 @@ class NavigationService { * @param skipReset whether to skip state reset (used for direct access scenario where reset is already handled) */ navigateToLogin() { - - this.resetAllApplicationState(); - useAuthStore.getState().logout(); - - if (this.navigate) { - this.navigate('/login'); + if (!this.navigate) { + console.error('Navigation function not set'); + return; } + + // First navigate to login page + this.navigate('/login'); + + // Then reset state after navigation + setTimeout(() => { + this.resetAllApplicationState(); + useAuthStore.getState().logout(); + }, 0); + } + + navigateToHome() { + if (!this.navigate) { + console.error('Navigation function not set'); + return; + } + + this.navigate('/'); } }