feat(webui): Display logged-in username

- Add username display in the `SiteHeader` component.
- Update logout button text to include username.
- Add `username` field in auth state.
- Optimize token parsing logic to extract username information.
- pre-commit fix
This commit is contained in:
Milin
2025-03-24 15:46:16 +08:00
parent 4dfdb9032c
commit b868dddac5
8 changed files with 204 additions and 177 deletions

View File

@@ -155,4 +155,4 @@ REDIS_URI=redis://localhost:6379
# AUTH_ACCOUNTS='admin:admin123,user1:pass456' # username:password,username:password
# TOKEN_SECRET=Your-Key-For-LightRAG-API-Server # JWT key
# TOKEN_EXPIRE_HOURS=4 # expire duration
# WHITELIST_PATHS= # white list
# WHITELIST_PATHS= # white list

View File

@@ -21,12 +21,12 @@ class AuthHandler:
self.algorithm = "HS256"
self.expire_hours = int(os.getenv("TOKEN_EXPIRE_HOURS", 4))
self.guest_expire_hours = int(os.getenv("GUEST_TOKEN_EXPIRE_HOURS", 2))
self.accounts = {}
auth_accounts = os.getenv("AUTH_ACCOUNTS")
if auth_accounts:
for account in auth_accounts.split(','):
username, password = account.split(':', 1)
for account in auth_accounts.split(","):
username, password = account.split(":", 1)
self.accounts[username] = password
def create_token(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="icon" type="image/svg+xml" href="logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lightrag</title>
<script type="module" crossorigin src="/webui/assets/index-DlScqWrq.js"></script>
<link rel="stylesheet" crossorigin href="/webui/assets/index-Cq65VeVX.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="icon" type="image/svg+xml" href="logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lightrag</title>
<script type="module" crossorigin src="/webui/assets/index-qXLILB5u.js"></script>
<link rel="stylesheet" crossorigin href="/webui/assets/index-BcBS1RaQ.css">
</head>
<body>
<div id="root"></div>
</body>

View File

@@ -55,7 +55,7 @@ function TabsNavigation() {
export default function SiteHeader() {
const { t } = useTranslation()
const { isGuestMode, coreVersion, apiVersion } = useAuthStore()
const { isGuestMode, coreVersion, apiVersion, username } = useAuthStore()
const versionDisplay = (coreVersion && apiVersion)
? `${coreVersion}/${apiVersion}`
@@ -96,7 +96,13 @@ export default function SiteHeader() {
</Button>
<AppSettings />
{!isGuestMode && (
<Button variant="ghost" size="icon" side="bottom" tooltip={t('header.logout')} onClick={handleLogout}>
<Button
variant="ghost"
size="icon"
side="bottom"
tooltip={`${t('header.logout')} (${username})`}
onClick={handleLogout}
>
<LogOutIcon className="size-4" aria-hidden="true" />
</Button>
)}

View File

@@ -21,6 +21,8 @@ interface AuthState {
isGuestMode: boolean; // Add guest mode flag
coreVersion: string | null;
apiVersion: string | null;
username: string | null; // login username
login: (token: string, isGuest?: boolean, coreVersion?: string | null, apiVersion?: string | null) => void;
logout: () => void;
setVersion: (coreVersion: string | null, apiVersion: string | null) => void;
@@ -76,36 +78,42 @@ const useBackendState = createSelectors(useBackendStateStoreBase)
export { useBackendState }
// Helper function to check if token is a guest token
const isGuestToken = (token: string): boolean => {
const parseTokenPayload = (token: string): { sub?: string; role?: string } => {
try {
// JWT tokens are in the format: header.payload.signature
const parts = token.split('.');
if (parts.length !== 3) return false;
// Decode the payload (second part)
if (parts.length !== 3) return {};
const payload = JSON.parse(atob(parts[1]));
// Check if the token has a role field with value "guest"
return payload.role === 'guest';
return payload;
} catch (e) {
console.error('Error parsing token:', e);
return false;
console.error('Error parsing token payload:', e);
return {};
}
};
// Initialize auth state from localStorage
const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; coreVersion: string | null; apiVersion: string | null } => {
const getUsernameFromToken = (token: string): string | null => {
const payload = parseTokenPayload(token);
return payload.sub || null;
};
const isGuestToken = (token: string): boolean => {
const payload = parseTokenPayload(token);
return payload.role === 'guest';
};
const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; coreVersion: string | null; apiVersion: string | null; username: string | null } => {
const token = localStorage.getItem('LIGHTRAG-API-TOKEN');
const coreVersion = localStorage.getItem('LIGHTRAG-CORE-VERSION');
const apiVersion = localStorage.getItem('LIGHTRAG-API-VERSION');
const username = token ? getUsernameFromToken(token) : null;
if (!token) {
return {
isAuthenticated: false,
isGuestMode: false,
coreVersion: coreVersion,
apiVersion: apiVersion
apiVersion: apiVersion,
username: null,
};
}
@@ -113,7 +121,8 @@ const initAuthState = (): { isAuthenticated: boolean; isGuestMode: boolean; core
isAuthenticated: true,
isGuestMode: isGuestToken(token),
coreVersion: coreVersion,
apiVersion: apiVersion
apiVersion: apiVersion,
username: username,
};
};
@@ -126,6 +135,7 @@ export const useAuthStore = create<AuthState>(set => {
isGuestMode: initialState.isGuestMode,
coreVersion: initialState.coreVersion,
apiVersion: initialState.apiVersion,
username: initialState.username,
login: (token, isGuest = false, coreVersion = null, apiVersion = null) => {
localStorage.setItem('LIGHTRAG-API-TOKEN', token);
@@ -137,11 +147,13 @@ export const useAuthStore = create<AuthState>(set => {
localStorage.setItem('LIGHTRAG-API-VERSION', apiVersion);
}
const username = getUsernameFromToken(token);
set({
isAuthenticated: true,
isGuestMode: isGuest,
username: username,
coreVersion: coreVersion,
apiVersion: apiVersion
apiVersion: apiVersion,
});
},
@@ -154,8 +166,9 @@ export const useAuthStore = create<AuthState>(set => {
set({
isAuthenticated: false,
isGuestMode: false,
username: null,
coreVersion: coreVersion,
apiVersion: apiVersion
apiVersion: apiVersion,
});
},