From d2d38bf7dd797dc92de84d7855e5406548ce74df Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Wed, 23 Nov 2022 10:49:55 -0600 Subject: [PATCH] defined protect function for access control on front end --- client/src/App.tsx | 39 +++++++++++++------------ client/src/components/pages/Profile.tsx | 20 ++++++++++--- client/src/components/ui/Navbar.tsx | 20 ++++++------- client/src/context/AuthContext.tsx | 4 +-- client/src/util/Protect.tsx | 29 ++++++++++++++++++ server/auth/middlewares.ts | 10 +------ server/routes/auth.ts | 25 +++++++--------- server/schemas/index.ts | 14 ++++----- 8 files changed, 96 insertions(+), 65 deletions(-) create mode 100644 client/src/util/Protect.tsx diff --git a/client/src/App.tsx b/client/src/App.tsx index 30607c8..6b077a1 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,5 +1,8 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { IUser } from './schemas'; +import { checkCredientials } from './util/apiUtils'; +import { AuthContext, defaultValue, IAuthContext } from './context/AuthContext'; import Browser from './components/pages/Browser'; import Collection from './components/pages/Collection'; import Login from './components/pages/Login'; @@ -7,18 +10,16 @@ import Profile from './components/pages/Profile'; import Recipe from './components/pages/Recipe'; import Register from './components/pages/Register'; import Welcome from './components/pages/Welcome'; -import { useAuthContext } from './context/AuthContext'; import './sass/App.scss' -import { IUser } from './schemas'; -import { checkCredientials } from './util/apiUtils'; function App() { - const authContext = useAuthContext(); + const [user, setUser] = useState({ user: undefined }); useEffect(() => { const wrapper = async () => { - const result = await checkCredientials(); - authContext.user = result; + const result: IAuthContext | undefined = await checkCredientials(); + if (result == undefined) setUser({ user: undefined }); + setUser(result!); } wrapper(); @@ -26,17 +27,19 @@ function App() { return ( -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
+ +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+
) } diff --git a/client/src/components/pages/Profile.tsx b/client/src/components/pages/Profile.tsx index d60d39e..02d8c00 100644 --- a/client/src/components/pages/Profile.tsx +++ b/client/src/components/pages/Profile.tsx @@ -1,9 +1,21 @@ -import { Page } from "../ui"; +import { useContext, useEffect, useState } from "react"; +import { IUser } from "../../schemas"; +import { useNavigate } from "react-router-dom"; +import { AuthContext, useAuthContext } from "../../context/AuthContext"; +import { Button, Page } from "../ui"; +import Protect from "../../util/Protect"; export default function Profile() { + const [message, setMessage] = useState(); + const { user } = useContext(AuthContext); + const navigate = useNavigate(); + return ( - -

Mikayla Dobson

-
+ +
+

{user!.firstname}'s Profile

+

Things and stuff!

+
+
) } \ No newline at end of file diff --git a/client/src/components/ui/Navbar.tsx b/client/src/components/ui/Navbar.tsx index 4f13cf6..c0efde9 100644 --- a/client/src/components/ui/Navbar.tsx +++ b/client/src/components/ui/Navbar.tsx @@ -1,14 +1,14 @@ -import { useState } from "react"; +import { useContext, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { useAuthContext } from "../../context/AuthContext"; +import { AuthContext } from "../../context/AuthContext"; +import { IUser } from "../../schemas"; import { attemptLogout } from "../../util/apiUtils"; import Button from "./Button"; import "/src/sass/components/Navbar.scss"; const Navbar = () => { - const authContext = useAuthContext(); + const { user } = useContext(AuthContext); const navigate = useNavigate(); - const [user, setUser] = useState('Mikayla'); const navbarLoggedIn = (
-

Hi, {authContext.user?.firstname}

+

Hi, {user?.firstname}

+ +
@@ -40,16 +42,12 @@ const Navbar = () => { navigate('/')}>RECIPIN
-

Hi, {authContext.user?.firstname}

+

Hi, {user?.firstname}

) - if (authContext.user) { - return navbarLoggedIn; - } else { - return navbarNotLoggedIn; - } + return user ? navbarLoggedIn : navbarNotLoggedIn; } export default Navbar; \ No newline at end of file diff --git a/client/src/context/AuthContext.tsx b/client/src/context/AuthContext.tsx index 0f67744..535442a 100644 --- a/client/src/context/AuthContext.tsx +++ b/client/src/context/AuthContext.tsx @@ -2,11 +2,11 @@ import { createContext, useContext } from "react"; import { IUser } from "../schemas"; -interface IAuthContext { +export interface IAuthContext { user?: IUser } -const defaultValue: IAuthContext = { +export const defaultValue: IAuthContext = { user: undefined, } diff --git a/client/src/util/Protect.tsx b/client/src/util/Protect.tsx new file mode 100644 index 0000000..77dae68 --- /dev/null +++ b/client/src/util/Protect.tsx @@ -0,0 +1,29 @@ +import { useContext } from "react"; +import { useNavigate } from "react-router-dom"; +import { Button, Page } from "../components/ui"; +import Divider from "../components/ui/Divider"; +import { AuthContext } from "../context/AuthContext"; + +export default function Protect({ children = <> }) { + const { user } = useContext(AuthContext); + const navigate = useNavigate(); + + if (!user) { + return ( + +
+

Hi there! You don't look too familiar.

+

To view the content on this page, please log in below:

+ + +
+
+ ) + } else { + return ( + + { children } + + ) + } +} \ No newline at end of file diff --git a/server/auth/middlewares.ts b/server/auth/middlewares.ts index 28d8804..d036ff0 100644 --- a/server/auth/middlewares.ts +++ b/server/auth/middlewares.ts @@ -1,17 +1,9 @@ import { NextFunction, Request, Response } from "express" export function restrictAccess(req: Request, res: Response, next: NextFunction) { - if (!req.isAuthenticated()) { - res.status(403).send({ message: "Access forbidden" }); - } else { - next(); - } -} - -export function checkAccess(req: Request, res: Response, next: NextFunction) { if (req.isAuthenticated()) { next(); } else { - res.status(403).send({ message: "Access forbidden" }); + res.send({ ok: false, user: undefined }) } } \ No newline at end of file diff --git a/server/routes/auth.ts b/server/routes/auth.ts index 2d2cb63..b5c5347 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -4,7 +4,7 @@ import { IUser, IUserAuth } from "../schemas"; import AuthService from "../auth"; import { UserCtl } from "../controllers"; import now from "../util/now"; -import { checkAccess, restrictAccess } from "../auth/middlewares"; +import { restrictAccess } from "../auth/middlewares"; import { Session } from "express-session"; const AuthInstance = new AuthService(); const UserControl = new UserCtl(); @@ -14,20 +14,17 @@ const router = Router(); export const authRoute = (app: Express, passport: PassportStatic) => { app.use('/auth', router); - router.get('/', checkAccess, (req, res, next) => { - if (req.isAuthenticated()) { - // @ts-ignore: does not recognize structure of req.user - const user = req.user?.user; - const userData: IUser = { - firstname: user.firstname, - lastname: user.lastname, - handle: user.handle, - email: user.email - } - res.send({ user: userData }); - } else { - res.status(403).send({ message: "Access forbidden" }); + router.get('/', restrictAccess, (req, res, next) => { + // @ts-ignore: does not recognize structure of req.user + const user = req.user?.user; + const userData: IUser = { + id: user.id, + firstname: user.firstname, + lastname: user.lastname, + handle: user.handle, + email: user.email } + res.send({ user: userData }); }) router.get('/protected', restrictAccess, (req, res, next) => { diff --git a/server/schemas/index.ts b/server/schemas/index.ts index 0d489da..b359e5c 100644 --- a/server/schemas/index.ts +++ b/server/schemas/index.ts @@ -1,9 +1,9 @@ -interface HasHistory { +interface HasHistory extends DBEntity { datecreated?: string datemodified?: string } -interface CanDeactivate { +interface CanDeactivate extends DBEntity { active?: boolean } @@ -11,7 +11,7 @@ interface DBEntity { id?: number } -export interface IUser extends DBEntity, HasHistory, CanDeactivate { +export interface IUser extends HasHistory, CanDeactivate { firstname: string lastname: string handle: string @@ -24,25 +24,25 @@ export interface IUserAuth { password: string } -export interface IRecipe extends DBEntity, HasHistory, CanDeactivate { +export interface IRecipe extends HasHistory, CanDeactivate { name: string description?: string preptime: string authoruserid?: IUser["id"] } -export interface IIngredient extends DBEntity, HasHistory { +export interface IIngredient extends HasHistory { name: string description?: string } -export interface ICollection extends DBEntity, HasHistory, CanDeactivate { +export interface ICollection extends HasHistory, CanDeactivate { name: string ismaincollection: boolean ownerid?: IUser["id"] } -export interface IGroceryList extends DBEntity, HasHistory, CanDeactivate { +export interface IGroceryList extends HasHistory, CanDeactivate { name: string ownerid?: IUser["id"] } \ No newline at end of file