mirror of
https://github.com/rustfs/console.git
synced 2026-11-03 14:44:58 +08:00
178 lines
5.0 KiB
TypeScript
178 lines
5.0 KiB
TypeScript
"use client"
|
|
|
|
import { createContext, useCallback, useContext, useMemo, type ReactNode } from "react"
|
|
import type { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@aws-sdk/types"
|
|
import { getStsToken } from "@/lib/sts"
|
|
import type { SiteConfig } from "@/types/config"
|
|
import { getLoginRoute } from "@/lib/routes"
|
|
import { useLocalStorage } from "@/hooks/use-local-storage"
|
|
|
|
interface Credentials {
|
|
AccessKeyId?: string
|
|
SecretAccessKey?: string
|
|
SessionToken?: string
|
|
Expiration?: string
|
|
}
|
|
|
|
interface AuthContextValue {
|
|
login: (
|
|
credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider,
|
|
customConfig?: SiteConfig,
|
|
) => Promise<unknown>
|
|
loginWithStsCredentials: (credentials: Credentials) => Promise<void>
|
|
logout: () => void
|
|
logoutAndRedirect: () => void
|
|
setIsAdmin: (value: boolean) => void
|
|
getIsAdmin: () => boolean
|
|
credentials: Credentials | undefined
|
|
permanentCredentials: Credentials | undefined
|
|
isAuthenticated: boolean
|
|
isAdmin: boolean
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextValue | null>(null)
|
|
|
|
function isValidCredentials(credentials: Credentials | undefined): boolean {
|
|
if (
|
|
!credentials?.AccessKeyId ||
|
|
!credentials?.SecretAccessKey ||
|
|
!credentials?.SessionToken ||
|
|
!credentials?.Expiration
|
|
) {
|
|
return false
|
|
}
|
|
const isExpired = (exp: string) => (exp ? new Date(exp) < new Date() : false)
|
|
return !isExpired(credentials.Expiration)
|
|
}
|
|
|
|
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
const [store, setStore] = useLocalStorage<Credentials | undefined>("auth.credentials", undefined)
|
|
const [isAdminStore, setIsAdminStore] = useLocalStorage<boolean | undefined>("auth.isAdmin", undefined)
|
|
const [permanentStore, setPermanentStore] = useLocalStorage<Credentials | undefined>("auth.permanent", undefined)
|
|
|
|
const setCredentials = useCallback(
|
|
(credentials: Credentials) => {
|
|
setStore(credentials)
|
|
},
|
|
[setStore],
|
|
)
|
|
|
|
const setPermanentCredentials = useCallback(
|
|
(credentials: Credentials) => {
|
|
setPermanentStore(credentials)
|
|
},
|
|
[setPermanentStore],
|
|
)
|
|
|
|
const getCredentials = useCallback(() => {
|
|
if (!isValidCredentials(store)) return undefined
|
|
return store
|
|
}, [store])
|
|
|
|
const setIsAdmin = useCallback(
|
|
(value: boolean) => {
|
|
setIsAdminStore(value)
|
|
},
|
|
[setIsAdminStore],
|
|
)
|
|
|
|
const getIsAdmin = useCallback(() => {
|
|
return !!isAdminStore
|
|
}, [isAdminStore])
|
|
|
|
const login = useCallback(
|
|
async (credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider, customConfig?: SiteConfig) => {
|
|
if (!customConfig) {
|
|
const { configManager } = await import("@/lib/config")
|
|
customConfig = await configManager.loadConfig()
|
|
}
|
|
|
|
const credentialsResponse = await getStsToken(credentials, "arn:aws:iam::*:role/Admin", customConfig)
|
|
|
|
setCredentials({
|
|
...credentialsResponse,
|
|
AccessKeyId: credentialsResponse.AccessKeyId,
|
|
SecretAccessKey: credentialsResponse.SecretAccessKey,
|
|
SessionToken: credentialsResponse.SessionToken,
|
|
Expiration: credentialsResponse.Expiration?.toISOString(),
|
|
})
|
|
|
|
if (typeof credentials === "object" && !("sessionToken" in credentials && credentials.sessionToken)) {
|
|
setPermanentCredentials({
|
|
AccessKeyId: credentials.accessKeyId,
|
|
SecretAccessKey: credentials.secretAccessKey,
|
|
})
|
|
} else {
|
|
setPermanentStore(undefined)
|
|
}
|
|
|
|
return credentialsResponse
|
|
},
|
|
[setCredentials, setPermanentCredentials, setPermanentStore],
|
|
)
|
|
|
|
const loginWithStsCredentials = useCallback(
|
|
async (creds: Credentials) => {
|
|
setCredentials({
|
|
AccessKeyId: creds.AccessKeyId,
|
|
SecretAccessKey: creds.SecretAccessKey,
|
|
SessionToken: creds.SessionToken,
|
|
Expiration: creds.Expiration,
|
|
})
|
|
setPermanentStore(undefined)
|
|
},
|
|
[setCredentials, setPermanentStore],
|
|
)
|
|
|
|
const logout = useCallback(() => {
|
|
setStore(undefined)
|
|
setPermanentStore(undefined)
|
|
setIsAdminStore(undefined)
|
|
}, [setStore, setPermanentStore, setIsAdminStore])
|
|
|
|
const logoutAndRedirect = useCallback(() => {
|
|
logout()
|
|
window.location.href = getLoginRoute()
|
|
}, [logout])
|
|
|
|
const credentials = getCredentials()
|
|
const isAuthenticated = isValidCredentials(store)
|
|
|
|
const value = useMemo<AuthContextValue>(
|
|
() => ({
|
|
login,
|
|
loginWithStsCredentials,
|
|
logout,
|
|
logoutAndRedirect,
|
|
setIsAdmin,
|
|
getIsAdmin,
|
|
credentials,
|
|
permanentCredentials: permanentStore,
|
|
isAuthenticated,
|
|
isAdmin: !!isAdminStore,
|
|
}),
|
|
[
|
|
login,
|
|
loginWithStsCredentials,
|
|
logout,
|
|
logoutAndRedirect,
|
|
setIsAdmin,
|
|
getIsAdmin,
|
|
credentials,
|
|
permanentStore,
|
|
isAuthenticated,
|
|
isAdminStore,
|
|
],
|
|
)
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
|
|
}
|
|
|
|
export function useAuth() {
|
|
const context = useContext(AuthContext)
|
|
if (!context) {
|
|
throw new Error("useAuth must be used within AuthProvider")
|
|
}
|
|
return context
|
|
}
|