mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-15 12:14:37 +00:00
- 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
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
// 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.
|
|
import { computed, ref } from 'vue'
|
|
import type { AccessLevel } from './types'
|
|
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, 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.
|
|
export async function fetchMe(): Promise<void> {
|
|
try {
|
|
const me = await api.me()
|
|
authLevel.value = me.level
|
|
authName.value = me.name
|
|
isAuthed.value = true
|
|
} catch {
|
|
// 401 (no/failed auth) — show the login page.
|
|
authLevel.value = 'read'
|
|
authName.value = ''
|
|
isAuthed.value = false
|
|
} finally {
|
|
authReady.value = true
|
|
}
|
|
}
|