fix(in-316): fix logout

pull/109/head
Ruslan Khayrullin 3 years ago
parent 8d069a4242
commit 7b3b0fe2c0
  1. 15
      public/silent-refresh.html
  2. 7
      src/features/AuthStore/config.tsx
  3. 2
      src/features/AuthStore/helpers.tsx
  4. 103
      src/features/AuthStore/hooks/useAuth.tsx
  5. 3
      src/helpers/index.tsx
  6. 4
      src/hooks/useEventListener.tsx
  7. 2
      src/requests/index.tsx

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.11.5/oidc-client.min.js" integrity="sha512-pGtU1n/6GJ8fu6bjYVGIOT9Dphaw5IWPwVlqkpvVgqBxFkvdNbytUh0H8AP15NYF777P4D3XEeA/uDWFCpSQ1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
new Oidc.UserManager().signinSilentCallback()
.catch((err) => {
console.error('OIDC: silent refresh callback error', err);
});
</script>
</body>
</html>

@ -0,0 +1,7 @@
import { UserManager } from 'oidc-client'
import { getClientSettings } from './helpers'
export const userManager = new UserManager(getClientSettings())
export const channel = new BroadcastChannel('access_token')

@ -61,7 +61,6 @@ const redirectUrl = () => {
export const getClientSettings = (): Settings => ({
authority: AUTH_SERVICE,
automaticSilentRenew: true,
client_id: client.auth.clientId,
filterProtocolClaims: false,
loadUserInfo: false,
@ -70,7 +69,6 @@ export const getClientSettings = (): Settings => ({
response_mode: 'query',
response_type: 'id_token token',
scope: 'openid',
silent_redirect_uri: `${window.location.origin ?? window.origin}/silent-refresh.html`,
userStore: new WebStorageStateStore({ store: window.localStorage }),
})

@ -7,7 +7,6 @@ import {
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'
@ -16,34 +15,33 @@ import { PAGES } from 'config'
import {
addLanguageUrlParam,
} from 'helpers/languageUrlParam'
import {
writeToken,
removeToken,
readToken,
} from 'helpers/token'
import {
setCookie,
removeCookie,
} from 'helpers/cookie'
import { isMatchPage } from 'helpers/isMatchPage'
isMatchPage,
} from 'helpers'
import {
useLocalStore,
useSessionStore,
useToggle,
useEventListener,
} from 'hooks'
import { useLexicsStore } from 'features/LexicsStore'
import { queryParamStorage } from 'features/QueryParamsStorage'
import { getUserInfo, UserInfo } from 'requests/getUserInfo'
import { checkDevice, FailedResponse } from 'requests/checkDevice'
import { getTokenVirtualUser } from 'requests/getTokenVirtualUser'
import type { UserInfo, FailedResponse } from 'requests'
import {
getUserInfo,
checkDevice,
getTokenVirtualUser,
} from 'requests'
// eslint-disable-next-line
import { getClientSettings, needCheckNewDeviсe } from '../helpers'
import { userManager, channel } from '../config'
import { needCheckNewDeviсe } from '../helpers'
export const useAuth = () => {
const { changeLang, lang } = useLexicsStore()
@ -55,11 +53,10 @@ export const useAuth = () => {
const [user, setUser] = useState<User>()
const [isNewDeviceLogin, setIsNewDeviceLogin] = useState(false)
const [userInfo, setUserInfo] = useState<UserInfo>()
const userManager = useMemo(() => new UserManager(getClientSettings()), [])
const login = useCallback(async () => {
userManager.signinRedirect({ extraQueryParams: { lang } })
}, [userManager, lang])
}, [lang])
const logout = useCallback((key?: string) => {
setPage(history.location.pathname)
@ -73,7 +70,7 @@ export const useAuth = () => {
removeCookie('access_token')
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userManager, lang])
}, [lang])
const storeUser = useCallback((loadedUser: User) => {
setUser(loadedUser)
@ -83,6 +80,8 @@ export const useAuth = () => {
name: 'access_token',
value: loadedUser.access_token,
})
// обновляем токен в других окнах/вкладках
channel.postMessage({ token: loadedUser.access_token })
}, [])
const checkUser = useCallback(async () => {
@ -102,7 +101,6 @@ export const useAuth = () => {
return loadedUser
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
userManager,
storeUser,
markUserLoaded,
])
@ -173,12 +171,31 @@ export const useAuth = () => {
}).catch(login)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
userManager,
login,
storeUser,
markUserLoaded,
])
useEventListener({
callback: useCallback(async (e: MessageEvent<{ token: string }>) => {
const loadedUser = await userManager.getUser()
if (
!e.data.token
|| !loadedUser
|| loadedUser.access_token === e.data.token
) return
userManager.storeUser({
...loadedUser,
access_token: e.data.token,
toStorageString: loadedUser.toStorageString,
})
}, []),
event: 'message',
target: channel,
})
useEffect(() => {
const isRedirectedBackFromAuthProvider = history.location.pathname === '/redirect'
isRedirectedBackFromAuthProvider ? signinRedirectCallback() : checkUser()
@ -200,34 +217,41 @@ export const useAuth = () => {
setTimeout(logout, 10000)
}
})
}, [logout, userManager])
}, [logout])
// eslint-disable-next-line
const checkNewDevice = useCallback(async () => {
const loadedUser = await userManager.getUser()
if (!loadedUser) return
checkDevice(loadedUser.access_token).catch(() => {
setTimeout(reChekNewDevice, 2000)
setTimeout(reChekNewDevice, 5000)
})
}, [reChekNewDevice, userManager])
// useEffect(() => {
// if (!needCheckNewDeviсe && !user) return undefined
// const startCheckDevice = setInterval(checkNewDevice, 20000)
// isNewDeviceLogin && clearInterval(startCheckDevice)
// return () => clearInterval(startCheckDevice)
//
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [
// checkNewDevice,
// isNewDeviceLogin,
// setIsNewDeviceLogin,
// ])
}, [reChekNewDevice])
useEffect(() => {
if (!needCheckNewDeviсe && !user) return undefined
const startCheckDevice = setInterval(checkNewDevice, 20000)
isNewDeviceLogin && clearInterval(startCheckDevice)
return () => clearInterval(startCheckDevice)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
checkNewDevice,
isNewDeviceLogin,
setIsNewDeviceLogin,
])
useEffect(() => {
// попытаемся обновить токен используя refresh_token
const tryRenewToken = () => {
const tokenLastUpdated = Number(localStorage.getItem('token_updated'))
// предотвращаем одновременное обновление токена в разных окнах/вкладках
const needRenewToken = Date.now() - tokenLastUpdated >= userManager.settings.clockSkew! * 1e3
if (!needRenewToken) return
localStorage.setItem('token_updated', String(Date.now()))
userManager.signinSilent()
.catch(() => user && logout())
}
@ -241,14 +265,7 @@ export const useAuth = () => {
userManager.events.removeAccessTokenExpired(tryRenewToken)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userManager, logout])
useEffect(() => {
// событие срабатывает после получения токена(первый
// логин и обновление токена)
userManager.events.addUserLoaded(storeUser)
return () => userManager.events.removeUserLoaded(storeUser)
}, [userManager, storeUser])
}, [logout])
const fetchUserInfo = useCallback(async () => {
try {

@ -11,3 +11,6 @@ export * from './selectedApi'
export * from './openSubscribePopup'
export * from './getCurrentYear'
export * from './getTeamAbbr'
export * from './cookie'
export * from './isMatchPage'
export * from './languageUrlParam'

@ -4,7 +4,7 @@ import { useEffect, useRef } from 'react'
type EventMap = HTMLElementEventMap & WindowEventMap
type Target = RefObject<HTMLElement> | HTMLElement | Window
type Target = RefObject<HTMLElement> | HTMLElement | Window | BroadcastChannel
type Args<E extends keyof EventMap> = {
callback: (e: EventMap[E]) => void,
@ -28,7 +28,7 @@ export const useEventListener = <E extends keyof EventMap>({
}, [callback])
useEffect(() => {
const windowOrElement: HTMLElement | Window | null = 'current' in target
const windowOrElement: HTMLElement | Window | BroadcastChannel | null = 'current' in target
? target.current
: target

@ -34,3 +34,5 @@ export * from './getTeamsStats'
export * from './getPlayersStats'
export * from './getMatchParticipants'
export * from './getStatsEvents'
export * from './getTokenVirtualUser'
export * from './checkDevice'

Loading…
Cancel
Save