-
Notifications
You must be signed in to change notification settings - Fork 4
/
AuthContext.tsx
132 lines (115 loc) · 4.1 KB
/
AuthContext.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import * as React from "react"
import LoginService from "../api/services/login"
import history from "../global/history"
import { noop } from "../global/utils"
import { AuthorizationType, TokenCodedType } from "../types/models"
import { fEmptyVoid } from "../types/types"
import APP_URLS from "../urls"
import Token from "./Token"
/** Hodnota zbývající platnosti tokenu, při které dojde k požadavku na jeho obnovení. */
const AUTH_REFRESH_THRESHOLD = 60 * 65 // sekundy -> 65 minut
type State = {
isLoading: boolean
isAuth: boolean
}
type Context = State & {
login: (credentials: AuthorizationType) => void
logout: fEmptyVoid
isAuthenticated: (refreshExpiringToken?: boolean) => void
}
/** Context pro správu přihlášení uživatele. */
const AuthContext = React.createContext<Context>({
isLoading: false,
isAuth: false,
isAuthenticated: noop,
login: noop,
logout: noop
})
type Props = {}
class AuthProvider extends React.Component<Props, State> {
state: State = {
isLoading: false,
isAuth: false
}
componentDidMount(): void {
this.isAuthenticated(false)
}
// prevod na sekundy (decoded.exp je v sekundach)
static getCurrentDate(): number {
return Date.now() / 1000
}
logout = (): void => {
Token.remove()
this.isAuthenticated(false)
// z jakekoliv stranky presmeruj uzivatele na prihlaseni (napr. na strance nenalezeno ho to jinak ponecha i po
// odhlaseni
history.push(APP_URLS.prihlasit.url)
}
isAuthenticated = (refreshExpiringToken = true): void => {
const token = Token.get()
this.setState({
isAuth: token !== null && !this.isTokenExpired(token, refreshExpiringToken)
})
}
isTokenExpired = (token: TokenCodedType, refreshExpiringToken: boolean): boolean => {
try {
const decodedToken = Token.decodeToken(token)
if (refreshExpiringToken) {
const dif = decodedToken.exp - AuthProvider.getCurrentDate()
Token.logToConsole(token, decodedToken, dif)
if (dif > 0 && dif <= AUTH_REFRESH_THRESHOLD) {
// token jeste plati, ale prodluz jeho platnost
this.refreshToken(token)
}
}
// je zaslany token expirovany? (pokud byl odeslan pozadavek na prodlouzeni platnosti, bere se i tak
// platnost puvodniho tokenu)
return decodedToken.exp < AuthProvider.getCurrentDate()
} catch (err) {
console.error(err)
return true
}
}
refreshToken = (token: TokenCodedType): void => {
const data = { token }
LoginService.refresh(data)
.then(({ token }) => {
Token.save(token)
this.isAuthenticated(false)
})
.catch(() => {
this.isAuthenticated(false)
alert(
"CHYBA - neúspěšný pokus o obnovení vašeho přihlášení. Přihlašte se, prosím, znovu!"
)
})
}
login = (credentials: AuthorizationType): void => {
this.setAuthLoading(true)
LoginService.authenticate(credentials)
.then(({ token }) => {
Token.save(token)
this.setAuthLoading(false)
})
.catch(() => this.setAuthLoading(false))
}
setAuthLoading = (newLoading: boolean): void => this.setState({ isLoading: newLoading })
componentDidUpdate(_prevProps: Props, prevState: State): void {
if (prevState.isLoading && !this.state.isLoading) {
this.isAuthenticated(false)
}
}
render = (): React.ReactNode => (
<AuthContext.Provider
value={{
isAuth: this.state.isAuth,
isLoading: this.state.isLoading,
isAuthenticated: this.isAuthenticated,
logout: this.logout,
login: this.login
}}>
{this.props.children}
</AuthContext.Provider>
)
}
export { AuthProvider, AuthContext }