From c42f08c0e6ad894f524e25565d075aeb07f36ca6 Mon Sep 17 00:00:00 2001 From: yangdx Date: Tue, 18 Mar 2025 19:45:43 +0800 Subject: [PATCH] Add navigation service for centralized login redirect routing - Simplify token validation logic in API - Update axios interceptor to use navigation service --- lightrag/api/utils_api.py | 39 ++++++++----------- lightrag_webui/src/App.tsx | 8 ++++ lightrag_webui/src/api/lightrag.ts | 27 +++++-------- .../src/features/DocumentManager.tsx | 1 - lightrag_webui/src/services/navigation.ts | 17 ++++++++ 5 files changed, 51 insertions(+), 41 deletions(-) create mode 100644 lightrag_webui/src/services/navigation.ts diff --git a/lightrag/api/utils_api.py b/lightrag/api/utils_api.py index adf855cc..9a8aaf57 100644 --- a/lightrag/api/utils_api.py +++ b/lightrag/api/utils_api.py @@ -42,45 +42,38 @@ def get_auth_dependency(): request: Request, token: str = Depends(OAuth2PasswordBearer(tokenUrl="login", auto_error=False)), ): - if request.url.path in whitelist: - return - # Check if authentication is configured auth_configured = bool( os.getenv("AUTH_USERNAME") and os.getenv("AUTH_PASSWORD") ) - # If authentication is not configured, accept any token including guest tokens + # If authentication is not configured, skip all validation if not auth_configured: - if token: # If token is provided, still validate it - try: - # Validate token but don't raise exception - token_info = auth_handler.validate_token(token) - # Check if it's a guest token - if token_info.get("role") != "guest": - # Non-guest tokens are not valid when auth is not configured - pass - except Exception as e: - # Ignore validation errors but log them - print(f"Token validation error (ignored): {str(e)}") return - # If authentication is configured, validate the token and reject guest tokens + # For configured auth, allow whitelist paths without token + if request.url.path in whitelist: + return + + # Require token for all other paths when auth is configured if not token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token required" ) - token_info = auth_handler.validate_token(token) - - # Reject guest tokens when authentication is configured - if token_info.get("role") == "guest": + try: + token_info = auth_handler.validate_token(token) + # Reject guest tokens when authentication is configured + if token_info.get("role") == "guest": + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Authentication required. Guest access not allowed when authentication is configured.", + ) + except Exception: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Authentication required. Guest access not allowed when authentication is configured.", + status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token" ) - # At this point, we have a valid non-guest token return return dependency diff --git a/lightrag_webui/src/App.tsx b/lightrag_webui/src/App.tsx index 102ff233..e6155c14 100644 --- a/lightrag_webui/src/App.tsx +++ b/lightrag_webui/src/App.tsx @@ -8,6 +8,8 @@ import { healthCheckInterval } from '@/lib/constants' import { useBackendState, useAuthStore } 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' @@ -19,7 +21,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) diff --git a/lightrag_webui/src/api/lightrag.ts b/lightrag_webui/src/api/lightrag.ts index ed063d21..0c9f1c0f 100644 --- a/lightrag_webui/src/api/lightrag.ts +++ b/lightrag_webui/src/api/lightrag.ts @@ -1,8 +1,9 @@ import axios, { AxiosError } from 'axios' -import { backendBaseUrl, webuiPrefix } from '@/lib/constants' +import { backendBaseUrl } from '@/lib/constants' import { errorMessage } from '@/lib/utils' import { useSettingsStore } from '@/stores/settings' import { useAuthStore } from '@/stores/state' +import { navigationService } from '@/services/navigation' // Types export type LightragNodeType = { @@ -157,21 +158,13 @@ axiosInstance.interceptors.request.use((config) => { const apiKey = useSettingsStore.getState().apiKey const token = localStorage.getItem('LIGHTRAG-API-TOKEN'); - // Check authentication status for paths that require authentication - const authRequiredPaths = ['/documents', '/graphs', '/query', '/health']; // Add all paths that require authentication - const isAuthRequired = authRequiredPaths.some(path => config.url?.includes(path)); - - if (isAuthRequired && !token && config.url !== '/login') { - // Cancel the request and return a rejected Promise - return Promise.reject(new Error('Authentication required')); - } - - if (apiKey) { - config.headers['X-API-Key'] = apiKey - } + // Always include token if it exists, regardless of path if (token) { config.headers['Authorization'] = `Bearer ${token}` } + if (apiKey) { + config.headers['X-API-Key'] = apiKey + } return config }) @@ -185,11 +178,11 @@ axiosInstance.interceptors.response.use( sessionStorage.clear(); useAuthStore.getState().logout(); - if (window.location.pathname !== `${webuiPrefix}/#/login`) { - window.location.href = `${webuiPrefix}/#/login`; - } + // Use navigation service to handle redirection + navigationService.navigateToLogin(); - return Promise.reject(error); + // Return a never-resolving promise to prevent further execution + return new Promise(() => {}); } throw new Error( `${error.response.status} ${error.response.statusText}\n${JSON.stringify( diff --git a/lightrag_webui/src/features/DocumentManager.tsx b/lightrag_webui/src/features/DocumentManager.tsx index c372b906..cfe3c894 100644 --- a/lightrag_webui/src/features/DocumentManager.tsx +++ b/lightrag_webui/src/features/DocumentManager.tsx @@ -45,7 +45,6 @@ export default function DocumentManager() { } else { setDocs(null) } - // console.log(docs) } else { setDocs(null) } diff --git a/lightrag_webui/src/services/navigation.ts b/lightrag_webui/src/services/navigation.ts new file mode 100644 index 00000000..88f286ee --- /dev/null +++ b/lightrag_webui/src/services/navigation.ts @@ -0,0 +1,17 @@ +import { NavigateFunction } from 'react-router-dom'; + +class NavigationService { + private navigate: NavigateFunction | null = null; + + setNavigate(navigate: NavigateFunction) { + this.navigate = navigate; + } + + navigateToLogin() { + if (this.navigate) { + this.navigate('/login'); + } + } +} + +export const navigationService = new NavigationService();