Implemented component version of authentication guard.

This commit is contained in:
Harrison Deng 2022-04-06 21:18:48 -05:00
parent 6856cd3b71
commit f98b003808
5 changed files with 64 additions and 77 deletions

View File

@ -1,6 +1,6 @@
import "./styles/Layout.css"; import "./styles/Layout.css";
import "./styles/extra.css"; import "./styles/extra.css";
import { useEffect, useState } from "react"; import { useContext } from "react";
import { NavLink, Route, Routes, useNavigate } from "react-router-dom"; import { NavLink, Route, Routes, useNavigate } from "react-router-dom";
import Welcome from "./pages/Welcome"; import Welcome from "./pages/Welcome";
import Navbar from "react-bootstrap/Navbar"; import Navbar from "react-bootstrap/Navbar";
@ -9,30 +9,14 @@ import NavbarToggle from "react-bootstrap/esm/NavbarToggle";
import NavbarCollapse from "react-bootstrap/esm/NavbarCollapse"; import NavbarCollapse from "react-bootstrap/esm/NavbarCollapse";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import Login from "./pages/Login"; import Login from "./pages/Login";
import { apiClient } from "./utils/httpClients";
import { globalContext } from "./context.js"; import { globalContext } from "./context.js";
export default function layout() { export default function layout() {
const navigate = useNavigate(); const navigate = useNavigate();
const [state, setState] = useState({
user: null,
});
useEffect(async () => { const context = useContext(globalContext);
await updateAuthStatus(); let identityDisplay = (
});
async function updateAuthStatus() {
const getUserResponse = await apiClient.get("/user");
if (getUserResponse !== 200) {
setState({ user: null });
} else {
setState({ user: getUserResponse.data });
}
}
let indentityDisplay = (
<Nav> <Nav>
<li className="nav-item"> <li className="nav-item">
<NavLink className="nav-link" to="/login" >Login</NavLink> <NavLink className="nav-link" to="/login" >Login</NavLink>
@ -43,8 +27,8 @@ export default function layout() {
</Nav> </Nav>
); );
if (state.user) { if (context.user) {
indentityDisplay = ( identityDisplay = (
<Nav> <Nav>
<li className="nav-item"> <li className="nav-item">
<NavLink className="nav-link" to="/" >Hi, {this.state.user.firstName}</NavLink> <NavLink className="nav-link" to="/" >Hi, {this.state.user.firstName}</NavLink>
@ -58,7 +42,7 @@ export default function layout() {
return ( return (
<div id="app"> <div id="app">
<globalContext.Provider value={{ navigate: navigate }}> <globalContext.Provider value={{ navigate: navigate, user: null }}>
<header> <header>
<Navbar bg="light" expand="md"> <Navbar bg="light" expand="md">
<Container> <Container>
@ -70,7 +54,7 @@ export default function layout() {
<NavLink className="nav-link" to="/" >Home</NavLink> <NavLink className="nav-link" to="/" >Home</NavLink>
</li> </li>
</Nav> </Nav>
{indentityDisplay} {identityDisplay}
</NavbarCollapse> </NavbarCollapse>
</Container> </Container>
</Navbar> </Navbar>

View File

@ -0,0 +1,30 @@
import React from "react";
import { Navigate } from "react-router-dom";
import { globalContext } from "../context";
import { apiClient } from "../utils/httpClients";
export default class AuthenticationGuard extends React.Component {
constructor(props) {
super(props);
}
async componentDidMount() {
if (!this.context.user) {
let userDataResponse = await apiClient.get("/user/");
if (userDataResponse.status === 200) {
this.context.user = userDataResponse.data;
}
}
}
static contextType = globalContext;
render() {
if (!this.context.user) {
return (
<Navigate to="/signup" replace="true" />
);
}
return;
}
}

View File

@ -5,7 +5,7 @@ import { apiClient } from "../utils/httpClients.js";
import MatchInfoCardDisplay from "../components/MatchInfoCardDisplay"; import MatchInfoCardDisplay from "../components/MatchInfoCardDisplay";
import SportInfoCardDisplay from "../components/SportInfoCardDisplay"; import SportInfoCardDisplay from "../components/SportInfoCardDisplay";
import { globalContext } from "../context"; import { globalContext } from "../context";
import { needUser } from "../utils/routing"; import AuthenticationGuard from "../components/AuthenticationGuard";
export default class Dashboard extends React.Component { export default class Dashboard extends React.Component {
constructor(props) { constructor(props) {
@ -21,7 +21,7 @@ export default class Dashboard extends React.Component {
static contextType = globalContext; static contextType = globalContext;
async componentDidMount() { async componentDidMount() {
await needUser(this.context.navigate); this.setState({ user: this.context.user });
await this.latestMatches(); await this.latestMatches();
await this.availableSports(); await this.availableSports();
} }
@ -41,6 +41,8 @@ export default class Dashboard extends React.Component {
render() { render() {
return ( return (
<div className="page-root">
<AuthenticationGuard />
<React.Fragment> <React.Fragment>
<h1></h1> <h1></h1>
<InputGroup className="w-50"> <InputGroup className="w-50">
@ -64,6 +66,7 @@ export default class Dashboard extends React.Component {
</React.Fragment> </React.Fragment>
</div>
); );
} }
} }

View File

@ -2,7 +2,7 @@ import React from "react";
import { Alert, Button, Card, Container, Form } from "react-bootstrap"; import { Alert, Button, Card, Container, Form } from "react-bootstrap";
import { globalContext } from "../context"; import { globalContext } from "../context";
import { apiClient } from "../utils/httpClients"; import { apiClient } from "../utils/httpClients";
import { guard } from "../utils/routing"; import AuthenticationGuard from "../components/AuthenticationGuard";
export default class Login extends React.Component { export default class Login extends React.Component {
constructor(props) { constructor(props) {
@ -19,14 +19,6 @@ export default class Login extends React.Component {
static contextType = globalContext; static contextType = globalContext;
async componentDidMount() { async componentDidMount() {
try {
const getUserResponse = await apiClient.get("/user");
guard(this.context.navigate, () => getUserResponse.status === 401, "/dashboard"); // If it's not 401, then we redirect to dashboard.
} catch (error) {
if (error.message !== "Request failed with status code 401") {
throw error;
}
}
} }
async attemptLogin(e) { async attemptLogin(e) {

View File

@ -1,22 +0,0 @@
import { apiClient } from "./httpClients";
export function guard(navigator, evaluator, redirect, navigateOptions, onRedirect) {
if (!evaluator) throw new Error("evaluator required.");
if (!redirect) throw new Error("redirect required.");
if (!navigateOptions) {
navigateOptions = {
replace: true
};
}
let redirecting = !evaluator();
if (redirecting) {
if (onRedirect) onRedirect();
navigator(redirect, navigateOptions);
}
}
export async function needUser(navigator) {
let userDataResponse = await apiClient.get("/user");
guard(navigator, () => userDataResponse.status === 200, "/login");
return userDataResponse.data;
}