defined protect function for access control on front end

This commit is contained in:
Mikayla Dobson
2022-11-23 10:49:55 -06:00
parent 7cc2851de7
commit d2d38bf7dd
8 changed files with 96 additions and 65 deletions

View File

@@ -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<IAuthContext>({ 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 (
<BrowserRouter>
<div className="App">
<Routes>
<Route path="/" element={<Welcome />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route path="/profile" element={<Profile />} />
<Route path="/collection" element={<Collection />} />
<Route path="/explore" element={<Browser />} />
<Route path="/recipe/:id" element={<Recipe />} />
</Routes>
</div>
<AuthContext.Provider value={ user }>
<div className="App">
<Routes>
<Route path="/" element={<Welcome />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route path="/profile" element={<Profile />} />
<Route path="/collection" element={<Collection />} />
<Route path="/explore" element={<Browser />} />
<Route path="/recipe/:id" element={<Recipe />} />
</Routes>
</div>
</AuthContext.Provider>
</BrowserRouter>
)
}

View File

@@ -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<JSX.Element>();
const { user } = useContext(AuthContext);
const navigate = useNavigate();
return (
<Page>
<h1>Mikayla Dobson</h1>
</Page>
<Protect>
<div className="profile-authenticated">
<h1>{user!.firstname}'s Profile</h1>
<p>Things and stuff!</p>
</div>
</Protect>
)
}

View File

@@ -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 = (
<div id="navbar">
@@ -16,8 +16,10 @@ const Navbar = () => {
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {authContext.user?.firstname}</p>
<p>Hi, {user?.firstname}</p>
<span id="search-icon"></span>
<Button onClick={() => console.log(user)}>Auth Context?</Button>
<Button onClick={() => navigate('/profile')}>Profile</Button>
<Button onClick={attemptLogout}>Log Out</Button>
</div>
</div>
@@ -40,16 +42,12 @@ const Navbar = () => {
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {authContext.user?.firstname}</p>
<p>Hi, {user?.firstname}</p>
</div>
</div>
)
if (authContext.user) {
return navbarLoggedIn;
} else {
return navbarNotLoggedIn;
}
return user ? navbarLoggedIn : navbarNotLoggedIn;
}
export default Navbar;

View File

@@ -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,
}

View File

@@ -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 (
<Page>
<div className="content-unauthorized">
<h1>Hi there! You don't look too familiar.</h1>
<p>To view the content on this page, please log in below:</p>
<Divider />
<Button onClick={() => navigate('/login')}>Log In</Button>
</div>
</Page>
)
} else {
return (
<Page>
{ children }
</Page>
)
}
}

View File

@@ -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 })
}
}

View File

@@ -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) => {

View File

@@ -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"]
}