From fdae186ce0f741b155a1313e08e304d05f38bcc4 Mon Sep 17 00:00:00 2001 From: Wellington Mazoni de Andrade Date: Wed, 1 May 2024 19:52:04 -0300 Subject: [PATCH] organizing utils --- frontend/src/AuthContext.ts | 3 +- frontend/src/components/Navbar/index.tsx | 16 +- .../src/components/PrivateRoute/index.tsx | 4 +- frontend/src/pages/Admin/Auth/Login/index.tsx | 44 ++++-- frontend/src/pages/Admin/Navbar/index.tsx | 2 +- frontend/src/util/auth.ts | 33 +++++ frontend/src/util/requests.ts | 137 +++++++----------- frontend/src/util/storage.ts | 21 +++ 8 files changed, 144 insertions(+), 116 deletions(-) create mode 100644 frontend/src/util/auth.ts create mode 100644 frontend/src/util/storage.ts diff --git a/frontend/src/AuthContext.ts b/frontend/src/AuthContext.ts index ec1f711..73cc862 100644 --- a/frontend/src/AuthContext.ts +++ b/frontend/src/AuthContext.ts @@ -1,5 +1,6 @@ import { createContext } from "react"; -import { TokenData } from "util/requests"; +import { TokenData } from "util/auth"; + export type AuthContextData = { authenticated: boolean; diff --git a/frontend/src/components/Navbar/index.tsx b/frontend/src/components/Navbar/index.tsx index 551ef30..08f487d 100644 --- a/frontend/src/components/Navbar/index.tsx +++ b/frontend/src/components/Navbar/index.tsx @@ -5,15 +5,11 @@ import { useContext, useEffect } from 'react'; import { Link, NavLink } from 'react-router-dom'; import history from 'util/history'; -import { - getTokenData, - isAuthenticated, - removeAuthData, -} from 'util/requests'; +import { getTokenData, isAuthenticated } from 'util/auth'; +import { removeAuthData } from 'util/storage'; const Navbar = () => { - - const {authContextData, setAuthContextData} = useContext(AuthContext) + const { authContextData, setAuthContextData } = useContext(AuthContext); useEffect(() => { if (isAuthenticated()) { @@ -74,10 +70,12 @@ const Navbar = () => { -
+
{authContextData.authenticated ? ( <> - {authContextData.tokenData?.user_name} + + {authContextData.tokenData?.user_name} + LOGOUT diff --git a/frontend/src/components/PrivateRoute/index.tsx b/frontend/src/components/PrivateRoute/index.tsx index 4c556a3..ccab32b 100644 --- a/frontend/src/components/PrivateRoute/index.tsx +++ b/frontend/src/components/PrivateRoute/index.tsx @@ -1,10 +1,10 @@ import { Redirect, Route } from 'react-router-dom'; -import { Role, hasAnyRoles, isAuthenticated } from 'util/requests'; +import { Role, hasAnyRoles, isAuthenticated } from 'util/auth'; type Props = { children: React.ReactNode; path: string; - roles?: Role[] + roles?: Role[]; }; const PrivateRoute = ({ children, path, roles = [] }: Props) => { diff --git a/frontend/src/pages/Admin/Auth/Login/index.tsx b/frontend/src/pages/Admin/Auth/Login/index.tsx index 1c95893..db66949 100644 --- a/frontend/src/pages/Admin/Auth/Login/index.tsx +++ b/frontend/src/pages/Admin/Auth/Login/index.tsx @@ -2,9 +2,11 @@ import { Link, useHistory, useLocation } from 'react-router-dom'; import ButtonIcon from 'components/ButtonIcon'; import { useForm } from 'react-hook-form'; import './styles.css'; -import { getTokenData, requestBackendLogin, saveAuthData } from 'util/requests'; +import { requestBackendLogin } from 'util/requests'; import { useContext, useState } from 'react'; import { AuthContext } from 'AuthContext'; +import { saveAuthData } from 'util/storage'; +import { getTokenData } from 'util/auth'; type FormData = { username: string; @@ -13,24 +15,28 @@ type FormData = { type LocationState = { from: string; -} +}; const Login = () => { const location = useLocation(); - const {from} = location.state || { from: { pathname: '/admin' } }; - const {setAuthContextData} = useContext(AuthContext) + const { from } = location.state || { from: { pathname: '/admin' } }; + const { setAuthContextData } = useContext(AuthContext); const [hasError, setHasError] = useState(false); - const { register, handleSubmit, formState: {errors} } = useForm(); + const { + register, + handleSubmit, + formState: { errors }, + } = useForm(); const history = useHistory(); const onSubmit = (formData: FormData) => { requestBackendLogin(formData) .then((response) => { - saveAuthData(response.data) + saveAuthData(response.data); setHasError(false); setAuthContextData({ authenticated: true, - tokenData: getTokenData() - }) + tokenData: getTokenData(), + }); history.replace(from); }) .catch((error) => { @@ -55,27 +61,35 @@ const Login = () => { required: 'Campo obrigatório', pattern: { value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, - message: 'Email inválido' - } + message: 'Email inválido', + }, })} type="text" - className={`form-control base-input ${errors.username ? 'is-invalid' : ''}`} + className={`form-control base-input ${ + errors.username ? 'is-invalid' : '' + }`} placeholder="Email" name="username" /> -
{errors.username?.message}
+
+ {errors.username?.message} +
-
{errors.password?.message}
+
+ {errors.password?.message} +
Esqueci a senha diff --git a/frontend/src/pages/Admin/Navbar/index.tsx b/frontend/src/pages/Admin/Navbar/index.tsx index 1f0504c..cbcd682 100644 --- a/frontend/src/pages/Admin/Navbar/index.tsx +++ b/frontend/src/pages/Admin/Navbar/index.tsx @@ -1,6 +1,6 @@ import { NavLink } from 'react-router-dom'; import './styles.css'; -import { hasAnyRoles } from 'util/requests'; +import { hasAnyRoles } from 'util/auth'; const Navbar = () => { return ( diff --git a/frontend/src/util/auth.ts b/frontend/src/util/auth.ts new file mode 100644 index 0000000..ef06b17 --- /dev/null +++ b/frontend/src/util/auth.ts @@ -0,0 +1,33 @@ +import jwtDecode from 'jwt-decode'; +import { getAuthData } from './storage'; + +export type Role = 'ROLE_OPERATOR' | 'ROLE_ADMIN'; + +export type TokenData = { + exp: number; + user_name: string; + authorities: Role[]; +}; + +export const getTokenData = (): TokenData | undefined => { + try { + return jwtDecode(getAuthData().access_token); + } catch (error) { + return undefined; + } +}; +export const isAuthenticated = (): boolean => { + const tokenData = getTokenData(); + return tokenData && tokenData.exp * 1000 > Date.now() ? true : false; +}; +export const hasAnyRoles = (roles: Role[]): boolean => { + if (roles.length === 0) { + return true; + } + const tokenData = getTokenData(); + + if (tokenData !== undefined) { + return roles.some((role) => tokenData.authorities.includes(role)); + } + return false; +}; diff --git a/frontend/src/util/requests.ts b/frontend/src/util/requests.ts index 6dbc24d..8611ed7 100644 --- a/frontend/src/util/requests.ts +++ b/frontend/src/util/requests.ts @@ -1,104 +1,65 @@ -import qs from 'qs' -import axios, { AxiosRequestConfig } from 'axios' -import history from './history' -import jwtDecode from 'jwt-decode'; +import qs from 'qs'; +import axios, { AxiosRequestConfig } from 'axios'; +import history from './history'; +import { getAuthData } from './storage'; -export type Role = 'ROLE_OPERATOR' | 'ROLE_ADMIN'; +export const BASE_URL = + process.env.REACT_APP_BACKEND_URL ?? 'http://localhost:8080'; -export type TokenData = { - exp: number, - user_name: string, - authorities: Role[] -} - -type LoginResponse = { - "access_token": string, - "token_type": string, - "expires_in": string, - "scope": string, - "userFirstName": string, - "userId": string -} - -export const BASE_URL = process.env.REACT_APP_BACKEND_URL ?? 'http://localhost:8080' -const tokenKey = 'authData' -const CLIENT_ID = process.env.REACT_APP_CLIENT_ID ?? 'dscatalog' -const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET ?? 'dscatalog123' -const basicHeader = () => 'Basic ' + window.btoa(CLIENT_ID + ':' + CLIENT_SECRET) +const CLIENT_ID = process.env.REACT_APP_CLIENT_ID ?? 'dscatalog'; +const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET ?? 'dscatalog123'; +const basicHeader = () => + 'Basic ' + window.btoa(CLIENT_ID + ':' + CLIENT_SECRET); type LoginData = { - username: string - password: string -} -export const requestBackendLogin = (loginData : LoginData) => { - const headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - Authorization: basicHeader() - } - const data = qs.stringify ({ - ...loginData, - grant_type: 'password' - }) - return axios({method: 'POST', baseURL: BASE_URL, url: '/oauth/token', data, headers}) -} - -export const saveAuthData = (obj : LoginResponse) => { - localStorage.setItem(tokenKey, JSON.stringify(obj)) -} - -export const getAuthData = () => { - const str = localStorage.getItem(tokenKey) ?? "{}" - return JSON.parse(str) as LoginResponse -} - -export const removeAuthData = () => { - localStorage.removeItem(tokenKey); -} + username: string; + password: string; +}; +export const requestBackendLogin = (loginData: LoginData) => { + const headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + Authorization: basicHeader(), + }; + const data = qs.stringify({ + ...loginData, + grant_type: 'password', + }); + return axios({ + method: 'POST', + baseURL: BASE_URL, + url: '/oauth/token', + data, + headers, + }); +}; export const requestBackend = (config: AxiosRequestConfig) => { - const headers = config.withCredentials ? { + const headers = config.withCredentials + ? { ...config.headers, - Authorization: "Bearer " + getAuthData().access_token - } : config.headers; - return axios({...config, baseURL: BASE_URL, headers}) -} + Authorization: 'Bearer ' + getAuthData().access_token, + } + : config.headers; + return axios({ ...config, baseURL: BASE_URL, headers }); +}; // Add a request interceptor -axios.interceptors.request.use(function (config) { +axios.interceptors.request.use( + function (config) { return config; - }, function (error) { + }, + function (error) { return Promise.reject(error); - }); + } +); -axios.interceptors.response.use(function (response) { +axios.interceptors.response.use( + function (response) { return response; - }, function (error) { + }, + function (error) { if (error.response.status === 401) { - history.push('/admin/auth') + history.push('/admin/auth'); } return Promise.reject(error); - }); - - export const getTokenData = () : TokenData | undefined => { - try { - return jwtDecode(getAuthData().access_token); - } catch (error) { - return undefined; - } - } - - export const isAuthenticated = () : boolean => { - const tokenData = getTokenData(); - return (tokenData && tokenData.exp * 1000 > Date.now()) ? true : false; } - - export const hasAnyRoles = (roles: Role[]) : boolean => { - if (roles.length === 0) { - return true; - } - const tokenData = getTokenData(); - - if (tokenData !== undefined) { - return roles.some(role => tokenData.authorities.includes(role)) - } - return false; - } \ No newline at end of file +); diff --git a/frontend/src/util/storage.ts b/frontend/src/util/storage.ts new file mode 100644 index 0000000..d13ae5d --- /dev/null +++ b/frontend/src/util/storage.ts @@ -0,0 +1,21 @@ +const tokenKey = 'authData'; +type LoginResponse = { + access_token: string; + token_type: string; + expires_in: string; + scope: string; + userFirstName: string; + userId: string; +}; +export const saveAuthData = (obj: LoginResponse) => { + localStorage.setItem(tokenKey, JSON.stringify(obj)); +}; + +export const getAuthData = () => { + const str = localStorage.getItem(tokenKey) ?? '{}'; + return JSON.parse(str) as LoginResponse; +}; + +export const removeAuthData = () => { + localStorage.removeItem(tokenKey); +};