47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { createSignal } from 'solid-js'
|
||
import { api } from './api'
|
||
import { auth } from './auth'
|
||
|
||
export interface AuthCheck {
|
||
status?: string
|
||
is_root?: boolean
|
||
is_admin?: boolean
|
||
|
||
enabled: boolean
|
||
authenticated: boolean
|
||
username?: string
|
||
role?: string
|
||
permissions?: Record<string, boolean>
|
||
}
|
||
|
||
const [check, setCheck] = createSignal<AuthCheck | null>(null)
|
||
|
||
export const permissions = {
|
||
check,
|
||
setCheck,
|
||
refresh: async () => {
|
||
try {
|
||
const c = await api.authCheck()
|
||
setCheck(c)
|
||
} catch {
|
||
setCheck(null)
|
||
}
|
||
},
|
||
// 能力判断(与 Casbin 策略一一对应):room:publish / room:subscribe / room:chat / user:manage ...
|
||
can: (action: string) => !!check()?.permissions?.[action],
|
||
// 当前角色:优先鉴权接口返回,回退到已登录用户信息
|
||
role: () => check()?.role ?? auth.user()?.role ?? 'guest',
|
||
status: () => (check() as any)?.status ?? (auth.user() as any)?.status ?? 'active',
|
||
isRoot: () => permissions.role() === 'root',
|
||
isAdmin: () => { const r = permissions.role(); return r === 'root' || r === 'admin' },
|
||
isAdminOrAbove: () => { const r = permissions.role(); return r === 'root' || r === 'admin' },
|
||
isBanned: () => permissions.status() === 'banned',
|
||
canManage: (targetRole: string) => {
|
||
const r = permissions.role()
|
||
if (r === 'root') return true
|
||
if (r === 'admin') return targetRole === 'viewer' || targetRole === 'publisher'
|
||
return false
|
||
},
|
||
isAuthed: () => !!auth.user() || !!check()?.authenticated,
|
||
}
|