Skip to content
Snippets Groups Projects
Commit 2aae30e3 authored by Albin Henriksson's avatar Albin Henriksson
Browse files

Create checkAuthentication for competition

parent e83beb62
No related branches found
No related tags found
1 merge request!115Resolve "Add authorization to socketio"
This commit is part of merge request !115. Comments created here will be created in the context of that merge request.
......@@ -20,14 +20,28 @@ const Main: React.FC = () => {
return (
<BrowserRouter>
<Switch>
<SecureRoute login exact path="/" component={LoginPage} />
<SecureRoute path="/admin" component={AdminPage} />
<SecureRoute path="/editor/competition-id=:competitionId" component={PresentationEditorPage} />
<SecureRoute authLevel={'login'} exact path="/" component={LoginPage} />
<SecureRoute authLevel={'admin'} path="/admin" component={AdminPage} />
<SecureRoute
authLevel={'admin'}
path="/editor/competition-id=:competitionId"
component={PresentationEditorPage}
/>
<Route exact path="/:code" component={ViewSelectPage} />
<Route exact path="/participant/id=:id&code=:code" component={ParticipantViewPage} />
<SecureRoute exact path="/presenter/id=:id&code=:code" component={PresenterViewPage} />
<Route exact path="/judge/id=:id&code=:code" component={JudgeViewPage} />
<Route exact path="/audience/id=:id&code=:code" component={AudienceViewPage} />
<SecureRoute
authLevel={'competition'}
exact
path="/participant/id=:id&code=:code"
component={ParticipantViewPage}
/>
<SecureRoute
authLevel={'competition'}
exact
path="/presenter/id=:id&code=:code"
component={PresenterViewPage}
/>
<SecureRoute authLevel={'competition'} exact path="/judge/id=:id&code=:code" component={JudgeViewPage} />
<SecureRoute authLevel={'competition'} exact path="/audience/id=:id&code=:code" component={AudienceViewPage} />
</Switch>
</BrowserRouter>
)
......
......@@ -26,3 +26,15 @@ export const loginCompetition = (code: string, history: History) => async (dispa
console.log(err)
})
}
// Log out from competition and remove jwt token from local storage and axios
export const logoutCompetition = () => async (dispatch: AppDispatch) => {
localStorage.removeItem('token')
await axios.post('/api/auth/logout').then(() => {
delete axios.defaults.headers.common['Authorization']
dispatch({
type: Types.SET_COMPETITION_LOGIN_UNAUTHENTICATED,
})
window.location.href = '/' //redirect to login page
})
}
......@@ -14,6 +14,8 @@ export default {
SET_SEARCH_USERS_TOTAL_COUNT: 'SET_SEARCH_USERS_TOTAL_COUNT',
SET_ERRORS: 'SET_ERRORS',
CLEAR_ERRORS: 'CLEAR_ERRORS',
SET_COMPETITION_LOGIN_AUTHENTICATED: 'SET_COMPETITION_LOGIN_AUTHENTICATED',
SET_COMPETITION_LOGIN_UNAUTHENTICATED: 'SET_COMPETITION_LOGIN_UNAUTHENTICATED',
SET_COMPETITION_LOGIN_ERRORS: 'SET_COMPETITION_LOGIN_ERRORS',
CLEAR_COMPETITION_LOGIN_ERRORS: 'CLEAR_COMPETITION_LOGIN_ERRORS',
SET_UNAUTHENTICATED: 'SET_UNAUTHENTICATED',
......
import React, { useEffect } from 'react'
import { Redirect, Route, RouteProps } from 'react-router-dom'
import { useAppSelector } from '../hooks'
import { CheckAuthentication } from './checkAuthentication'
import { CheckAuthenticationAdmin } from './checkAuthenticationAdmin'
import { CheckAuthenticationCompetition } from './checkAuthenticationCompetition'
interface SecureRouteProps extends RouteProps {
login?: boolean
component: React.ComponentType<any>
rest?: any
authLevel: 'competition' | 'admin' | 'login'
}
/** Utility component to use for authentication, replace all routes that should be private with secure routes*/
const SecureRoute: React.FC<SecureRouteProps> = ({ login, component: Component, ...rest }: SecureRouteProps) => {
const SecureRoute: React.FC<SecureRouteProps> = ({
login,
component: Component,
authLevel,
...rest
}: SecureRouteProps) => {
const authenticated = useAppSelector((state) => state.user.authenticated)
const [initialized, setInitialized] = React.useState(false)
useEffect(() => {
const waitForAuthentication = async () => {
await CheckAuthentication()
if (authLevel === 'admin' || authLevel === 'login') {
await CheckAuthenticationAdmin()
} else {
await CheckAuthenticationCompetition()
}
setInitialized(true)
}
waitForAuthentication()
}, [])
if (initialized) {
if (login)
if (authLevel === 'login')
return (
<Route {...rest} render={(props) => (authenticated ? <Redirect to="/admin" /> : <Component {...props} />)} />
)
......
import mockedAxios from 'axios'
import Types from '../actions/types'
import store from '../store'
import { CheckAuthentication } from './checkAuthentication'
import { CheckAuthenticationAdmin } from './CheckAuthenticationAdmin'
it('dispatches correct actions when auth token is ok', async () => {
const userRes: any = {
......@@ -20,7 +20,7 @@ it('dispatches correct actions when auth token is ok', async () => {
const testToken =
'Bearer eyJ0eXAiOiJeyJ0eXAiOiJKV1QeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSciLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxScKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSc'
localStorage.setItem('token', testToken)
await CheckAuthentication()
await CheckAuthenticationAdmin()
expect(spy).toBeCalledWith({ type: Types.LOADING_USER })
expect(spy).toBeCalledWith({ type: Types.SET_AUTHENTICATED })
expect(spy).toBeCalledWith({ type: Types.SET_USER, payload: userRes.data })
......@@ -39,7 +39,7 @@ it('dispatches correct actions when getting user data fails', async () => {
const testToken =
'Bearer eyJ0eXAiOiJeyJ0eXAiOiJKV1QeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSciLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxScKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSc'
localStorage.setItem('token', testToken)
await CheckAuthentication()
await CheckAuthenticationAdmin()
expect(spy).toBeCalledWith({ type: Types.LOADING_USER })
expect(spy).toBeCalledWith({ type: Types.SET_UNAUTHENTICATED })
expect(spy).toBeCalledTimes(2)
......@@ -51,7 +51,7 @@ it('dispatches no actions when no token exists', async () => {
return Promise.resolve({ data: {} })
})
const spy = jest.spyOn(store, 'dispatch')
await CheckAuthentication()
await CheckAuthenticationAdmin()
expect(spy).not.toBeCalled()
})
......@@ -63,7 +63,7 @@ it('dispatches correct actions when token is expired', async () => {
'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDY1MTUsImV4cCI6MTU4Njc3MDUxNSwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.R5-oWGGumd-YWPoKyziJmVB8SdX6B9SsV6m7novIfgg'
localStorage.setItem('token', testToken)
const spy = jest.spyOn(store, 'dispatch')
await CheckAuthentication()
await CheckAuthenticationAdmin()
expect(spy).toBeCalledWith({ type: Types.SET_UNAUTHENTICATED })
expect(spy).toBeCalledTimes(1)
})
......@@ -8,7 +8,7 @@ const UnAuthorized = async () => {
await logoutUser()(store.dispatch)
}
export const CheckAuthentication = async () => {
export const CheckAuthenticationAdmin = async () => {
const authToken = localStorage.token
if (authToken) {
const decodedToken: any = jwtDecode(authToken)
......
import axios from 'axios'
import jwtDecode from 'jwt-decode'
import { logoutCompetition } from '../actions/competitionLogin'
import Types from '../actions/types'
import { logoutUser } from '../actions/user'
import store from '../store'
const UnAuthorized = async () => {
await logoutCompetition()(store.dispatch)
}
export const CheckAuthenticationCompetition = async () => {
const authToken = localStorage.competitionToken
if (authToken) {
const decodedToken: any = jwtDecode(authToken)
if (decodedToken.exp * 1000 >= Date.now()) {
axios.defaults.headers.common['Authorization'] = authToken
await axios
.get('/api/auth/test')
.then((res) => {
store.dispatch({ type: Types.SET_COMPETITION_LOGIN_AUTHENTICATED })
})
.catch((error) => {
console.log(error)
UnAuthorized()
})
} else {
await UnAuthorized()
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment