Skip to content
Snippets Groups Projects
Commit 0d436a47 authored by Defendi Alberto's avatar Defendi Alberto
Browse files

Merge branch 'feature/privateroute/role' into 'dev'

New route type (RestrictedRoute) and better api calls.

See merge request !44
parents 1de11a10 e8f5de30
No related branches found
No related tags found
2 merge requests!56Refined auth flow and new website pages.,!44New route type (RestrictedRoute) and better api calls.
Pipeline #12197 passed
Showing
with 116 additions and 52 deletions
......@@ -8,7 +8,6 @@ import {
createMuiTheme,
responsiveFontSizes,
MuiThemeProvider,
Container,
Dialog,
DialogActions,
DialogContent,
......@@ -20,7 +19,7 @@ import {
import AddIcon from '@material-ui/icons/Add';
import Fab from '@material-ui/core/Fab';
import { Reservation } from 'components/AuthUser/ReservationPage/Reservation/Reservation';
import { Reservation } from 'components/AuthUser/Dashboard/ReservationPage/Reservation/Reservation';
import { NavBar } from '../HomePage/NavBar';
let themeResp = createMuiTheme();
......
export type CredentialsType = {
username: string;
password: string;
};
......@@ -6,51 +6,44 @@ import { InputField } from 'components/AuthUser/InputField/InputField';
import { useHistory } from 'react-router-dom';
import { AuthRoutes } from 'api/routes';
import { AuthContext } from 'components/AuthUser/AuthContext';
import { fetchCookie } from 'api/fetchCookie';
import { useStyles } from './useStyles';
import { CredentialsType } from './CredentialsType';
const configDjangoCookieName = (): void => {
axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN';
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.withCredentials = true;
const defaultValues = {
username: '',
password: '',
};
export const SignInForm: FC = () => {
const [isCookieFetched, setisCookieFetched] = useState<string>('');
configDjangoCookieName();
useEffect(() => {
const fetchCookie = async (): Promise<unknown> => {
const response = await axios('/api/web/csrf');
setisCookieFetched(response.data.token);
return null;
};
if (!isCookieFetched) fetchCookie();
}, [isCookieFetched]);
const history = useHistory();
const { setRole } = useContext(AuthContext);
const { setRole, setIsAuth } = useContext(AuthContext);
const [cookie, setCookie] = useState<string>('');
interface FormData {
username: string;
password: string;
}
useEffect(() => {
let isMounted = true;
if (isMounted)
fetchCookie().then((cookieResponse) => setCookie(cookieResponse));
const defaultValues: FormData = {
username: '',
password: '',
};
return () => {
isMounted = false;
};
}, [cookie]);
const { control, errors, setError, handleSubmit } = useForm<FormData>({
const { control, errors, setError, handleSubmit } = useForm<CredentialsType>({
defaultValues,
});
const onSubmit: SubmitHandler<FormData> = (values: FormData) => {
const onSubmit: SubmitHandler<CredentialsType> = (
values: CredentialsType,
) => {
axios
.post(
'/api/web/login',
{
username: values.username,
password: values.password,
csrfmiddlewaretoken: isCookieFetched,
csrfmiddlewaretoken: cookie,
},
{
headers: {
......@@ -70,7 +63,8 @@ export const SignInForm: FC = () => {
});
} else if (response.data.status === 'success') {
setRole(response.data.role);
history.replace(AuthRoutes.dashboard);
setIsAuth(true);
history.replace(`${AuthRoutes.dashboard}${AuthRoutes.home}`);
}
});
};
......
import axios from 'axios';
import { CredentialsType } from './CredentialsType';
export const postCredentials = async (
values: CredentialsType,
cookie: React.Dispatch<React.SetStateAction<string>>,
): Promise<unknown> => {
const response = await axios.post(
'/api/web/login',
{
username: values.username,
password: values.password,
csrfmiddlewaretoken: cookie,
},
{
headers: {
'Content-Type': 'application/json',
},
},
);
return null;
};
import React, { useState, useEffect, useContext } from 'react';
import axios from 'axios';
import React, { useContext } from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { NonAuthRoutes } from 'api/routes';
import { AuthContext } from 'components/AuthUser/AuthContext';
import { Roles } from 'api/userRoles';
/**
* A wrapper for <Route> that redirects to the login screen if you're not yet authenticated.
* Every non-public route must be wrapped with this component.
* */
type Props = {
Component: React.FC<RouteProps>;
path: string;
......@@ -22,24 +19,11 @@ export const PrivateRoute = ({
path,
requiredRoles,
}: Props): JSX.Element => {
const [auth, setAuth] = useState<boolean>(false);
const { role } = useContext(AuthContext);
const { role, isAuth } = useContext(AuthContext);
useEffect(() => {
const fetch = async (): Promise<unknown> => {
const result = await axios('/api/web/login/is_authenticated');
setAuth(result.data.is_authenticated);
return null;
};
/*
Check if user is logged in.
Avoiding this condition would call is\_authenticated every time
this component state is triggered, falling in unnecessary calls to the
server.
*/
if (role !== Roles.visitor) fetch();
}, [auth]);
// Check if the role is contained in the roles array (passed as props).
const userHasRequiredRole = requiredRoles.includes(role);
const message = userHasRequiredRole
? 'Please log in to view this page'
: 'Your role is not allowed';
......@@ -49,12 +33,12 @@ export const PrivateRoute = ({
exact={false}
path={path}
render={(props: RouteProps) =>
auth && userHasRequiredRole ? (
isAuth && userHasRequiredRole ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: userHasRequiredRole
pathname: !userHasRequiredRole
? `${NonAuthRoutes.auth}${NonAuthRoutes.signIn}`
: NonAuthRoutes.unauthorized,
state: {
......
import React, { useState, useEffect } from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { AuthRoutes } from 'api/routes';
import { isAuthenticated } from 'api/isAuthenticated';
import { CircularProgress } from '@material-ui/core';
/**
*
* */
type Props = {
Component: React.FC<RouteProps>;
path: string;
};
/**
* Wrapper for Route that basing on if the user is authenticated,
* redirects to:
* - Entry point of the private route (the homepage);
* - Login page.
*/
/* eslint-disable react/jsx-props-no-spreading */
export const RestrictedRoute = ({ Component, path }: Props): JSX.Element => {
const [isAuth, setIsAuth] = useState<boolean>(false);
const [isLoading, setLoading] = useState<boolean>(false);
useEffect(() => {
let isMounted = true;
isAuthenticated().then((state) => {
if (isMounted) {
setIsAuth(state);
setLoading(true);
}
});
return () => {
isMounted = false;
};
}, [isLoading]);
return !isLoading ? (
<CircularProgress />
) : (
<Route
path={path}
render={(props: RouteProps) =>
!isAuth ? (
// Redirect to component.
<Component {...props} />
) : (
// Redirect to homepage.
<Redirect
to={{ pathname: `${AuthRoutes.dashboard}${AuthRoutes.home}` }}
/>
)
}
/>
);
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment