mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-15 12:14:37 +00:00
feat: session-cookie login/logout + three-tier roles (superadmin/admin/viewer) with read-only UI + remove pink theme
- cookie-based auth (/login /logout) replacing Basic Auth for UI, enabling logout - roles: superadmin (account management only), admin (full except accounts), viewer/audit (read-only status+cluster, export logs) - readonly accounts hide edit buttons (added remote node, group ops, canvas layout/save/import, cluster manage, install) instead of greying them - auditors see status+cluster only; ordinary admins lose the accounts nav; last-admin guard covers superadmin - remove pink theme entirely (switcher, [data-theme=pink], leftover localStorage), keep white/blue
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
// Lightweight reactive auth principal for the SPA. The browser handles Basic
|
||||
// Auth (prompted once when the SPA shell loads behind auth("read")); this just
|
||||
// mirrors the resolved identity from GET /me so views can gate their UI.
|
||||
// Lightweight reactive auth principal for the SPA. Since the switch to
|
||||
// session-cookie login (POST /api/manager/login), the SPA no longer relies on
|
||||
// the browser's Basic Auth: on mount we resolve GET /me — a session cookie
|
||||
// makes it 200 (signed in); otherwise it is 401 and the login page shows.
|
||||
// logout() clears the cookie server-side, so sign-out actually sticks.
|
||||
//
|
||||
// We default to read until /me resolves so a viewer never sees a flash of
|
||||
// admin controls. canWrite/isAdmin are memoized over the reactive level.
|
||||
@ -11,11 +13,37 @@ import { api } from './api'
|
||||
export const authLevel = ref<AccessLevel>('read')
|
||||
export const authName = ref('')
|
||||
export const authReady = ref(false)
|
||||
export const isAuthed = ref(false)
|
||||
|
||||
const RANK: Record<AccessLevel, number> = { read: 1, write: 2, admin: 3 }
|
||||
const RANK: Record<AccessLevel, number> = { read: 1, write: 2, admin: 3, superadmin: 4 }
|
||||
|
||||
export const canWrite = computed(() => RANK[authLevel.value] >= RANK.write)
|
||||
// admin: full write access but cannot manage accounts (that needs superadmin).
|
||||
export const isAdmin = computed(() => authLevel.value === 'admin')
|
||||
// superadmin: the only tier that can manage accounts (users/apikeys routes).
|
||||
export const isSuperAdmin = computed(() => authLevel.value === 'superadmin')
|
||||
|
||||
// login signs in via the session-cookie endpoint and mirrors the resolved
|
||||
// principal. Call from the login page; on success App.vue drops into the shell.
|
||||
export async function login(username: string, password: string): Promise<void> {
|
||||
const me = await api.login(username, password)
|
||||
authLevel.value = me.level
|
||||
authName.value = me.name
|
||||
isAuthed.value = true
|
||||
authReady.value = true
|
||||
}
|
||||
|
||||
// logout clears the UI session and returns to the login page.
|
||||
export async function logout(): Promise<void> {
|
||||
try {
|
||||
await api.logout()
|
||||
} catch {
|
||||
// session cookie may already be gone; still reset local state
|
||||
}
|
||||
authLevel.value = 'read'
|
||||
authName.value = ''
|
||||
isAuthed.value = false
|
||||
}
|
||||
|
||||
// fetchMe resolves the current principal. Called once on app mount; safe to
|
||||
// call again after account changes that could affect the live session.
|
||||
@ -24,10 +52,12 @@ export async function fetchMe(): Promise<void> {
|
||||
const me = await api.me()
|
||||
authLevel.value = me.level
|
||||
authName.value = me.name
|
||||
isAuthed.value = true
|
||||
} catch {
|
||||
// 401 (no/failed auth) — stay read-only; the browser will have prompted.
|
||||
// 401 (no/failed auth) — show the login page.
|
||||
authLevel.value = 'read'
|
||||
authName.value = ''
|
||||
isAuthed.value = false
|
||||
} finally {
|
||||
authReady.value = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user