Require accessToken to browse pages
This commit is contained in:
committed by
Anders Borch
parent
4655544197
commit
049664b98e
@ -5,6 +5,7 @@ import AuthCallback from './pages/auth/Callback';
|
|||||||
import Login from './pages/auth/Login';
|
import Login from './pages/auth/Login';
|
||||||
import AppLayout from './layout/AppLayout';
|
import AppLayout from './layout/AppLayout';
|
||||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||||
|
import RequireAuth from './components/auth/RequireAuth';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const user = {
|
const user = {
|
||||||
@ -25,9 +26,30 @@ function App() {
|
|||||||
{
|
{
|
||||||
<AppLayout user={user} workspace={workspace}>
|
<AppLayout user={user} workspace={workspace}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to="/people" replace />} />
|
<Route
|
||||||
<Route path="/people" element={<People />} />
|
path="/"
|
||||||
<Route path="/companies" element={<Companies />} />
|
element={
|
||||||
|
<RequireAuth>
|
||||||
|
<Navigate to="/people" replace />
|
||||||
|
</RequireAuth>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/people"
|
||||||
|
element={
|
||||||
|
<RequireAuth>
|
||||||
|
<People />
|
||||||
|
</RequireAuth>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/companies"
|
||||||
|
element={
|
||||||
|
<RequireAuth>
|
||||||
|
<Companies />
|
||||||
|
</RequireAuth>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path="/auth/callback" element={<AuthCallback />} />
|
<Route path="/auth/callback" element={<AuthCallback />} />
|
||||||
<Route path="/auth/login" element={<Login />} />
|
<Route path="/auth/login" element={<Login />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
19
front/src/components/auth/RequireAuth.tsx
Normal file
19
front/src/components/auth/RequireAuth.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useHasAccessToken } from '../../hooks/auth/useHasAccessToken';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
function RequireAuth({ children }: { children: JSX.Element }): JSX.Element {
|
||||||
|
const hasAccessToken = useHasAccessToken();
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasAccessToken) {
|
||||||
|
navigate('/auth/login');
|
||||||
|
}
|
||||||
|
}, [hasAccessToken, navigate]);
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RequireAuth;
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import RequireAuth from '../RequireAuth';
|
||||||
|
|
||||||
|
const component = {
|
||||||
|
title: 'RequireAuth',
|
||||||
|
component: RequireAuth,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default component;
|
||||||
|
|
||||||
|
export const RequireAuthWithHelloChild = () => (
|
||||||
|
<MemoryRouter>
|
||||||
|
<RequireAuth>
|
||||||
|
<div>Hello</div>
|
||||||
|
</RequireAuth>
|
||||||
|
</MemoryRouter>
|
||||||
|
);
|
||||||
9
front/src/components/auth/__tests__/RequireAuth.test.tsx
Normal file
9
front/src/components/auth/__tests__/RequireAuth.test.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { RequireAuthWithHelloChild } from '../__stories__/RequireAuth.stories';
|
||||||
|
|
||||||
|
it('Checks the Require Auth renders', () => {
|
||||||
|
const { getAllByText } = render(<RequireAuthWithHelloChild />);
|
||||||
|
|
||||||
|
expect(getAllByText('Hello')).toBeTruthy();
|
||||||
|
});
|
||||||
32
front/src/hooks/auth/__tests__/useHasAccessToken.test.tsx
Normal file
32
front/src/hooks/auth/__tests__/useHasAccessToken.test.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { render, waitFor } from '@testing-library/react';
|
||||||
|
import { useHasAccessToken } from '../useHasAccessToken';
|
||||||
|
|
||||||
|
function TestComponent() {
|
||||||
|
const hasAccessToken = useHasAccessToken();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>{hasAccessToken && <div data-testid="has-access-token"></div>}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('useHasAccessToken works properly if access token is present', async () => {
|
||||||
|
localStorage.setItem('accessToken', 'test-access-token');
|
||||||
|
const { getByTestId } = render(<TestComponent />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(getByTestId('has-access-token')).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('useHasAccessToken works properly if access token is not present', async () => {
|
||||||
|
localStorage.removeItem('accessToken');
|
||||||
|
const { container } = render(<TestComponent />);
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(container.firstChild).toBeEmptyDOMElement();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
@ -1,25 +1,6 @@
|
|||||||
import { render, waitFor } from '@testing-library/react';
|
import { render, waitFor } from '@testing-library/react';
|
||||||
import { useRefreshToken } from '../useRefreshToken';
|
import { useRefreshToken } from '../useRefreshToken';
|
||||||
|
|
||||||
const localStorageMock = (function () {
|
|
||||||
let store: { [key: string]: string } = {};
|
|
||||||
return {
|
|
||||||
getItem: function (key: string) {
|
|
||||||
return store[key];
|
|
||||||
},
|
|
||||||
setItem: function (key: string, value: string) {
|
|
||||||
store[key] = value.toString();
|
|
||||||
},
|
|
||||||
clear: function () {
|
|
||||||
store = {};
|
|
||||||
},
|
|
||||||
removeItem: function (key: string) {
|
|
||||||
delete store[key];
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
Object.defineProperty(window, 'localStorage', { value: localStorageMock });
|
|
||||||
|
|
||||||
function TestComponent() {
|
function TestComponent() {
|
||||||
const { loading } = useRefreshToken();
|
const { loading } = useRefreshToken();
|
||||||
|
|
||||||
@ -47,10 +28,11 @@ test('useRefreshToken works properly', async () => {
|
|||||||
render(<TestComponent />);
|
render(<TestComponent />);
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(localStorageMock.getItem('accessToken')).toBe('test-access-token');
|
expect(localStorage.getItem('accessToken')).toBe('test-access-token');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
localStorage.removeItem('refreshToken');
|
||||||
});
|
});
|
||||||
|
|||||||
5
front/src/hooks/auth/useHasAccessToken.tsx
Normal file
5
front/src/hooks/auth/useHasAccessToken.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const useHasAccessToken = () => {
|
||||||
|
const accessToken = localStorage.getItem('accessToken');
|
||||||
|
|
||||||
|
return accessToken ? true : false;
|
||||||
|
};
|
||||||
@ -1,16 +1,18 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useHasAccessToken } from '../../hooks/auth/useHasAccessToken';
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
const refreshToken = localStorage.getItem('refreshToken');
|
const hasAccessToken = useHasAccessToken();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!refreshToken) {
|
if (!hasAccessToken) {
|
||||||
window.location.href =
|
window.location.href =
|
||||||
process.env.REACT_APP_AUTH_URL + '/signin/provider/google' || '';
|
process.env.REACT_APP_AUTH_URL + '/signin/provider/google' || '';
|
||||||
|
} else {
|
||||||
|
navigate('/');
|
||||||
}
|
}
|
||||||
navigate('/');
|
}, [hasAccessToken, navigate]);
|
||||||
}, [refreshToken, navigate]);
|
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user