parent
de7a4b6d52
commit
92fd933c60
@ -0,0 +1,17 @@ |
||||
export interface AuthenticationInterface { |
||||
key: string |
||||
token(): string |
||||
} |
||||
|
||||
export class BearerAuthentication implements AuthenticationInterface { |
||||
key = 'Authorization' |
||||
_token: string |
||||
|
||||
constructor(token: string) { |
||||
this._token = token |
||||
} |
||||
|
||||
token(): string { |
||||
return `Bearer ${this._token}`; |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
import React from 'react' |
||||
import {UseTokenInterface} from "../hooks/use-token" |
||||
|
||||
const Context = React.createContext({} as UseTokenInterface) |
||||
export const Provider = Context.Provider |
||||
export default Context |
@ -0,0 +1,120 @@ |
||||
|
||||
|
||||
export interface TokenData<T=any> { |
||||
payload: T |
||||
headers: Record<string, any> |
||||
} |
||||
|
||||
const isClient = () => { |
||||
return typeof window !== 'undefined' |
||||
} |
||||
|
||||
export const storeToken = (token: string) => { |
||||
if (!isClient()) { |
||||
return; |
||||
} |
||||
let tokenData = grabTokenData(token) |
||||
let tokenId = tokenData?.payload?.id; |
||||
if (!tokenId) { |
||||
return; |
||||
} |
||||
|
||||
let tokens: string | null = window.localStorage.getItem('tokens') |
||||
let tokensData: string[] = JSON.parse(tokens || '[]'); |
||||
if (!tokensData) { |
||||
return |
||||
} |
||||
window.localStorage.setItem('token', tokenId) |
||||
window.localStorage.setItem(tokenId, token) |
||||
tokensData.push(tokenId) |
||||
window.localStorage.setItem('tokens', JSON.stringify(tokensData)) |
||||
} |
||||
|
||||
export const cleanToken = (id: string) => { |
||||
if (!isClient()) { |
||||
return; |
||||
} |
||||
let tokens: string | null = window.localStorage.getItem('tokens') |
||||
let tokensData: string[] = JSON.parse(tokens || '[]'); |
||||
if (!tokensData) { |
||||
return |
||||
} |
||||
|
||||
tokensData = tokensData.filter((storedTokenId: string) => storedTokenId !== id) |
||||
window.localStorage.setItem('tokens', JSON.stringify(tokensData)) |
||||
window.localStorage.removeItem(id) |
||||
|
||||
// Чистим текущий токен
|
||||
let activeTokenId: string | null = window.localStorage.getItem('token') |
||||
if (id === activeTokenId) { |
||||
window.localStorage.removeItem('token') |
||||
} |
||||
} |
||||
|
||||
export const selectToken = (id: string) => { |
||||
if (!isClient()) { |
||||
return; |
||||
} |
||||
window.localStorage.setItem('token', id) |
||||
} |
||||
|
||||
export const grabTokenData = (token: string): TokenData|null => { |
||||
if (!isClient()) { |
||||
return null |
||||
} |
||||
const parts = token.split('.') |
||||
let payload = 3 === parts.length && parts[1] ? JSON.parse(window.atob(parts[1])) : null |
||||
let headers = 3 === parts.length && parts[0] ? JSON.parse(window.atob(parts[0])) : null |
||||
if (!payload || !headers){ |
||||
return null |
||||
} |
||||
return { |
||||
payload, |
||||
headers, |
||||
}; |
||||
} |
||||
|
||||
export const grabRawToken = (): string | null => { |
||||
if (!isClient()) { |
||||
return null |
||||
} |
||||
const tokenId = window.localStorage.getItem('token') |
||||
if (!tokenId) { |
||||
return null |
||||
} |
||||
return window.localStorage.getItem(tokenId) |
||||
} |
||||
|
||||
export const grabToken = (): TokenData | null => { |
||||
const token = grabRawToken() |
||||
if (!token) { |
||||
return null |
||||
} |
||||
return grabTokenData(token); |
||||
} |
||||
|
||||
export const grabTokens = (): TokenData[] => { |
||||
if (!isClient()) { |
||||
return [] |
||||
} |
||||
const storedTokens = window.localStorage.getItem('tokens') |
||||
let tokens: string[] = JSON.parse(storedTokens || '[]'); |
||||
if (!tokens) { |
||||
return [] |
||||
} |
||||
|
||||
let result: TokenData[] = [] |
||||
|
||||
tokens.forEach((tokenId) => { |
||||
let token = window.localStorage.getItem(tokenId) |
||||
if (!token) { |
||||
return true |
||||
} |
||||
let tokenData = grabTokenData(token) |
||||
if (tokenData) { |
||||
result.push(tokenData) |
||||
} |
||||
}) |
||||
|
||||
return result |
||||
} |
@ -0,0 +1,30 @@ |
||||
import {useContext, useEffect, useState} from 'react' |
||||
import {SMClient} from "../api/sm/sm-client"; |
||||
import Context from "../context/token"; |
||||
import {Token} from "./use-token"; |
||||
import {BearerAuthentication} from "../api/authentication"; |
||||
import {grabRawToken} from "../functions/token"; |
||||
|
||||
const grabClient = (token: Token | null, rawToken: string | null): SMClient => { |
||||
let authentication = {} |
||||
if (rawToken) { |
||||
authentication = { |
||||
authentication: new BearerAuthentication(rawToken) |
||||
} |
||||
} |
||||
return new SMClient({ |
||||
baseUrl: 'http://' + (token?.host || 'localhost'), |
||||
...authentication |
||||
}) |
||||
} |
||||
|
||||
export function useApi(): SMClient { |
||||
let {token} = useContext(Context) |
||||
let [client, setClient] = useState<SMClient>(grabClient(token, grabRawToken())) |
||||
|
||||
useEffect(() => { |
||||
setClient(grabClient(token, grabRawToken())) |
||||
}, [token]) |
||||
|
||||
return client |
||||
} |
@ -0,0 +1,48 @@ |
||||
import {useState, useEffect} from 'react' |
||||
import {cleanToken, grabToken, grabTokens, selectToken, storeToken} from "../functions/token"; |
||||
|
||||
export class Token { |
||||
id!: string |
||||
host!: string |
||||
permissions!: string[] |
||||
} |
||||
|
||||
export interface UseTokenInterface { |
||||
token: Token|null |
||||
tokens: Token[] |
||||
switchToken(tokenId: string): void |
||||
deleteToken(tokenId: string): void |
||||
addToken(tokenId: string): void |
||||
} |
||||
|
||||
export function useToken(): UseTokenInterface { |
||||
const [token, setToken] = useState<Token|null>(null); |
||||
const [tokens, setTokens] = useState<Token[]>([]); |
||||
useEffect(() => { |
||||
setToken(grabToken()?.payload) |
||||
|
||||
let tokens = grabTokens().map((tokenData) => tokenData.payload) |
||||
setTokens(tokens) |
||||
|
||||
return () => { |
||||
|
||||
} |
||||
}, []) |
||||
|
||||
const switchToken = (tokenId: string) => { |
||||
selectToken(tokenId) |
||||
setToken(grabToken()?.payload) |
||||
} |
||||
|
||||
const deleteToken = (tokenId: string) => { |
||||
cleanToken(tokenId) |
||||
setToken(grabToken()?.payload) |
||||
} |
||||
|
||||
const addToken = (token: string) => { |
||||
storeToken(token) |
||||
setToken(grabToken()?.payload) |
||||
} |
||||
|
||||
return {token, tokens, switchToken, deleteToken, addToken} |
||||
} |
@ -1,6 +1,13 @@ |
||||
import '../styles/globals.css' |
||||
import type { AppProps } from 'next/app' |
||||
import {Provider} from "../context/token"; |
||||
import {useToken} from "../hooks/use-token"; |
||||
|
||||
export default function App({ Component, pageProps }: AppProps) { |
||||
return <Component {...pageProps} /> |
||||
let {token, tokens, switchToken, deleteToken, addToken} = useToken() |
||||
return ( |
||||
<Provider value={{token, tokens, switchToken, deleteToken, addToken}}> |
||||
<Component {...pageProps} /> |
||||
</Provider> |
||||
) |
||||
} |
||||
|
Loading…
Reference in new issue