You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
6.0 KiB
228 lines
6.0 KiB
import {
|
|
useCallback,
|
|
useState,
|
|
useMemo,
|
|
useEffect,
|
|
} from 'react'
|
|
import { useHistory } from 'react-router'
|
|
|
|
import type { User } from 'oidc-client'
|
|
import { UserManager } from 'oidc-client'
|
|
|
|
import isString from 'lodash/isString'
|
|
import isBoolean from 'lodash/isBoolean'
|
|
|
|
import { PAGES } from 'config'
|
|
|
|
import {
|
|
addLanguageUrlParam,
|
|
} from 'helpers/languageUrlParam'
|
|
import { writeToken, removeToken } from 'helpers/token'
|
|
import { setCookie, removeCookie } from 'helpers/cookie'
|
|
import { isMatchPage, isMatchPageRFEF } from 'helpers/isMatchPage'
|
|
|
|
import { useLocalStore, useToggle } from 'hooks'
|
|
|
|
import { useLexicsStore } from 'features/LexicsStore'
|
|
import { queryParamStorage } from 'features/QueryParamsStorage'
|
|
|
|
import { getUserInfo } from 'requests/getUserInfo'
|
|
import { checkDevice, FailedResponse } from 'requests/checkDevice'
|
|
|
|
import { getClientSettings, needCheckNewDeviсe } from '../helpers'
|
|
|
|
export const useAuth = () => {
|
|
const { changeLang, lang } = useLexicsStore()
|
|
const history = useHistory()
|
|
const {
|
|
close: markUserLoaded,
|
|
isOpen: loadingUser,
|
|
} = useToggle(true)
|
|
const [user, setUser] = useState<User>()
|
|
const [isNewDeviceLogin, setIsNewDeviceLogin] = useState(false)
|
|
const userManager = useMemo(() => new UserManager(getClientSettings()), [])
|
|
|
|
const login = useCallback(async () => (
|
|
userManager.signinRedirect({ extraQueryParams: { lang } })
|
|
), [userManager, lang])
|
|
|
|
const logout = useCallback(() => {
|
|
userManager.clearStaleState()
|
|
userManager.createSigninRequest().then(({ url }) => {
|
|
const urlWithLang = addLanguageUrlParam(lang, url)
|
|
userManager.signoutRedirect({ post_logout_redirect_uri: urlWithLang })
|
|
})
|
|
removeToken()
|
|
removeCookie('access_token')
|
|
}, [userManager, lang])
|
|
|
|
const storeUser = useCallback((loadedUser: User) => {
|
|
setUser(loadedUser)
|
|
writeToken(loadedUser.access_token)
|
|
setCookie({
|
|
exdays: 1,
|
|
name: 'access_token',
|
|
value: loadedUser.access_token,
|
|
})
|
|
}, [])
|
|
|
|
const checkUser = useCallback(async () => {
|
|
const loadedUser = await userManager.getUser()
|
|
if (!loadedUser) return Promise.reject()
|
|
|
|
storeUser(loadedUser)
|
|
markUserLoaded()
|
|
return loadedUser
|
|
}, [
|
|
userManager,
|
|
storeUser,
|
|
markUserLoaded,
|
|
])
|
|
|
|
const [page, setPage] = useLocalStore({
|
|
clearOnUnmount: true,
|
|
defaultValue: '',
|
|
key: 'matchBackLocation',
|
|
validator: isString,
|
|
})
|
|
|
|
const [search, setSearch] = useLocalStore({
|
|
clearOnUnmount: true,
|
|
defaultValue: '',
|
|
key: 'searchBack',
|
|
validator: isString,
|
|
})
|
|
|
|
const signinRedirectCallback = useCallback(() => {
|
|
userManager.signinRedirectCallback()
|
|
.then((loadedUser) => {
|
|
storeUser(loadedUser)
|
|
queryParamStorage.clear()
|
|
history.replace(PAGES.home)
|
|
markUserLoaded()
|
|
if (page) {
|
|
const route = `${page}${page === '/' ? search : ''}`
|
|
history.push(route)
|
|
setPage('')
|
|
setSearch('')
|
|
}
|
|
}).catch(login)
|
|
}, [
|
|
userManager,
|
|
login,
|
|
storeUser,
|
|
history,
|
|
markUserLoaded,
|
|
page,
|
|
search,
|
|
setPage,
|
|
setSearch,
|
|
])
|
|
|
|
useEffect(() => {
|
|
const isRedirectedBackFromAuthProvider = history.location.pathname === '/redirect'
|
|
if (isRedirectedBackFromAuthProvider) {
|
|
signinRedirectCallback()
|
|
} else {
|
|
checkUser().catch(() => {
|
|
if (!isMatchPage() && !isMatchPageRFEF()) {
|
|
login()
|
|
}
|
|
|
|
if (history.location.pathname === '/') {
|
|
setSearch(history.location.search)
|
|
}
|
|
setPage(history.location.pathname)
|
|
})
|
|
}
|
|
}, [
|
|
checkUser,
|
|
signinRedirectCallback,
|
|
login,
|
|
setPage,
|
|
setSearch,
|
|
history,
|
|
])
|
|
|
|
const reChekNewDevice = useCallback(async () => {
|
|
const loadedUser = await userManager.getUser()
|
|
if (!loadedUser) return
|
|
|
|
checkDevice(loadedUser.access_token).catch((er:FailedResponse) => {
|
|
if (er.error) return
|
|
if (isBoolean(er.ok) && !er.ok) {
|
|
setIsNewDeviceLogin(true)
|
|
setTimeout(logout, 10000)
|
|
}
|
|
})
|
|
}, [logout, userManager])
|
|
|
|
const checkNewDevice = useCallback(async () => {
|
|
const loadedUser = await userManager.getUser()
|
|
if (!loadedUser) return
|
|
|
|
checkDevice(loadedUser.access_token).catch(() => {
|
|
setTimeout(reChekNewDevice, 2000)
|
|
})
|
|
}, [reChekNewDevice, userManager])
|
|
|
|
useEffect(() => {
|
|
if (!needCheckNewDeviсe) return undefined
|
|
const startCheckDevice = setInterval(checkNewDevice, 20000)
|
|
isNewDeviceLogin && clearInterval(startCheckDevice)
|
|
return () => clearInterval(startCheckDevice)
|
|
}, [checkNewDevice,
|
|
isNewDeviceLogin,
|
|
setIsNewDeviceLogin,
|
|
])
|
|
|
|
useEffect(() => {
|
|
// попытаемся обновить токен используя refresh_token
|
|
const tryRenewToken = () => {
|
|
userManager.signinSilent().catch(logout)
|
|
}
|
|
// если запросы вернули 401 | 403
|
|
window.addEventListener('FORBIDDEN_REQUEST', tryRenewToken)
|
|
|
|
// и если токен истек
|
|
userManager.events.addAccessTokenExpired(tryRenewToken)
|
|
return () => {
|
|
window.removeEventListener('FORBIDDEN_REQUEST', tryRenewToken)
|
|
userManager.events.removeAccessTokenExpired(tryRenewToken)
|
|
}
|
|
}, [userManager, logout])
|
|
|
|
useEffect(() => {
|
|
// событие срабатывает после получения токена(первый
|
|
// логин и обновление токена)
|
|
userManager.events.addUserLoaded(storeUser)
|
|
return () => userManager.events.removeUserLoaded(storeUser)
|
|
}, [userManager, storeUser])
|
|
|
|
const fetchUserInfo = useCallback(async () => {
|
|
const userInfoFetched = await getUserInfo()
|
|
userInfoFetched.language.iso && changeLang(userInfoFetched.language.iso)
|
|
}, [changeLang])
|
|
|
|
useEffect(() => {
|
|
if (user) {
|
|
fetchUserInfo()
|
|
}
|
|
}, [fetchUserInfo, user])
|
|
|
|
const auth = useMemo(() => ({
|
|
isNewDeviceLogin,
|
|
loadingUser,
|
|
login,
|
|
logout,
|
|
user,
|
|
}), [
|
|
isNewDeviceLogin,
|
|
logout,
|
|
user,
|
|
login,
|
|
loadingUser,
|
|
])
|
|
|
|
return auth
|
|
}
|
|
|