Skip to content

Commit

Permalink
Merge pull request EpamLifeSciencesTeam#10 from AlekseiLitkovetc/add-…
Browse files Browse the repository at this point in the history
…authentication-logic

feat: Add authentication logic
  • Loading branch information
YBogomolov authored Jun 22, 2021
2 parents 197ce7d + 6626ebc commit 3ea2289
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 129 deletions.
127 changes: 19 additions & 108 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { FunctionComponent, useState } from 'react';
import React, { FC, useEffect, useState } from 'react';
import SignIn from './containers/Auth/SignIn/SignIn';
import SignUp from './containers/Auth/SignUp/SignUp';
import { Redirect, Route, Switch } from 'react-router';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from './store';
import { Dashboard } from './containers/Dashboard/Dashboard';
import { Box, Container, Grid, makeStyles, Paper, Theme } from '@material-ui/core';
import classNames from 'classnames';
import { LocaleContext, LocaleLanguage } from './context/LocaleContext';
import { authenticateUser } from "./store/auth/actions";


export const useStyles = makeStyles((theme: Theme) => ({
Expand All @@ -32,7 +33,7 @@ export const useStyles = makeStyles((theme: Theme) => ({
}
}));

const App: FunctionComponent = () => {
const App: FC = () => {

const [locale, setLocale] = useState(LocaleLanguage.en);

Expand All @@ -42,6 +43,13 @@ const App: FunctionComponent = () => {
[classes.fixedHeight]: true
});
const isAuthenticated = useSelector<RootState, boolean>(state => state.auth.isAuthenticated);
const dispatch = useDispatch();

useEffect(() => {
if (!isAuthenticated && localStorage.getItem('accessToken')) {
dispatch(authenticateUser);
}
});

const content = () => {
if (isAuthenticated) {
Expand Down
37 changes: 36 additions & 1 deletion src/axiosCromwell.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,45 @@
import axios from 'axios';
import { useDispatch } from "react-redux";
import { identity } from "./utils/FunctionUtils";
import { sessionExpired } from "./store/auth/actions";

const axiosCromwell = axios.create({
baseURL: 'http://localhost:3001/',
baseURL: 'http://localhost:8080/',
headers: {
'Content-Type': 'application/json'
}
});

axiosCromwell.interceptors.request.use(
config => {
const accessToken = localStorage.getItem('accessToken');
if (accessToken) {
config.headers['Authorization'] = accessToken;
}
return config;
},
Promise.reject
);

axiosCromwell.interceptors.response.use(
identity,
async error => {
const originalRequest = error.config;
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken && error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const tokensResponse = await axiosCromwell.get('/auth/refresh', {params: {refreshToken}})
if (tokensResponse.status === 200) {
localStorage.setItem('accessToken', tokensResponse.headers['access-token']);
localStorage.setItem('refreshToken', tokensResponse.headers['refresh-token']);
return axios(originalRequest);
}
} else if (refreshToken && error.response.status === 401 && originalRequest._retry) {
const dispatch = useDispatch();
dispatch(sessionExpired);
}
return Promise.reject(error);
}
);

export default axiosCromwell;
2 changes: 1 addition & 1 deletion src/containers/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Dashboard: FC = props => {
};

const signOutHandler = () => {
dispatch(signOut());
dispatch(signOut);
};

return (
Expand Down
42 changes: 33 additions & 9 deletions src/store/auth/actions.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,55 @@
import {
AUTH_AUTHENTICATE_USER,
AUTH_SESSION_EXPIRED,
AUTH_SIGN_IN_SUCCESS,
AUTH_SIGN_OUT,
AUTH_SIGN_UP_SUCCESS,
AuthActionTypes,
AuthHeaders,
SignInData,
SignUpData
} from './types';
import { CmwlThunkAction } from '../index';
import axiosCromwell from '../../axiosCromwell';
import { AxiosResponse } from "axios";

const signInSuccess = (): AuthActionTypes => ({
type: AUTH_SIGN_IN_SUCCESS
const signInSuccess = (authHeaders: AuthHeaders): AuthActionTypes => ({
type: AUTH_SIGN_IN_SUCCESS,
authHeaders: authHeaders
});

const signUpSuccess = (): AuthActionTypes => ({
type: AUTH_SIGN_UP_SUCCESS
const signUpSuccess = (authHeaders: AuthHeaders): AuthActionTypes => ({
type: AUTH_SIGN_UP_SUCCESS,
authHeaders: authHeaders
});

export const signIn = (signInData: SignInData): CmwlThunkAction => (dispatch => {
dispatch(signInSuccess());
// ToDo: Add axios async call
axiosCromwell.post('/auth/signIn', signInData).then(response => {
const authHeaders = getAuthHeaders(response);
dispatch(signInSuccess(authHeaders));
}).catch(error => console.log(error))
});

export const signUp = (signUpData: SignUpData): CmwlThunkAction => (dispatch => {
dispatch(signUpSuccess());
// ToDo: Add axios async call
axiosCromwell.post('/auth/signUp', signUpData).then(response => {
const authHeaders = getAuthHeaders(response);
dispatch(signUpSuccess(authHeaders));
}).catch(error => console.log(error))
});

export const signOut = (): AuthActionTypes => ({
export const authenticateUser: AuthActionTypes = {
type: AUTH_AUTHENTICATE_USER
}

export const signOut: AuthActionTypes = {
type: AUTH_SIGN_OUT
}

export const sessionExpired: AuthActionTypes = {
type: AUTH_SESSION_EXPIRED
}

const getAuthHeaders = (response: AxiosResponse): AuthHeaders => ({
accessToken: response.headers['access-token'],
refreshToken: response.headers['refresh-token']
});
Loading

0 comments on commit 3ea2289

Please sign in to comment.