The auth routes should seem familiar. We only add one that returns the logged in user.
constexpress=require('express');constrouter=express.Router();constUser=require('../models/User');constbcrypt=require('bcrypt');constpassport=require('passport');router.post('/signup',(req,res)=>{const{ username, password }=req.body;if(!password||password.length<8){returnres.status(400).json({message: 'Your password must be 8 char. min.'});}if(!username){returnres.status(400).json({message: 'Your username cannot be empty'});}User.findOne({username: username}).then(found=>{if(found){returnres.status(400).json({message: 'This username is already taken'});}constsalt=bcrypt.genSaltSync();consthash=bcrypt.hashSync(password,salt);returnUser.create({username: username,password: hash}).then(dbUser=>{req.login(dbUser,err=>{if(err){returnres.status(500).json({message: 'Error while attempting to login'});}res.json(dbUser);});});}).catch(err=>{res.json(err);});});router.post('/login',(req,res)=>{passport.authenticate('local',(err,user)=>{if(err){returnres.status(500).json({message: 'Error while authenticating'});}if(!user){returnres.status(400).json({message: 'Wrong credentials'});}req.login(user,err=>{if(err){returnres.status(500).json({message: 'Error while attempting to login'});}returnres.json(user);});})(req,res);});router.delete('/logout',(req,res)=>{req.logout();res.json({message: 'Successful logout'});});// returns the logged in userrouter.get('/loggedin',(req,res)=>{res.json(req.user);});module.exports=router;
When our app starts we want to first check if there is a logged in User in the session and then give this user to App.js as a prop.
// index.jsimportReactfrom'react';importReactDOMfrom'react-dom';import{BrowserRouter}from'react-router-dom';import'./index.css';importAppfrom'./App';import*asserviceWorkerfrom'./serviceWorker';// import axiosimportaxiosfrom'axios';// get logged in user and pass it as a propaxios.get('/api/auth/loggedin').then(response=>{constuser=response.data;ReactDOM.render(<BrowserRouter><Appuser={user}/></BrowserRouter>,document.getElementById('root'));});//
We want to use a Signup component in the App.js - here we also add the user to the state
Therefore we turn App.js into a class component.
And we also have to add the state and the setState for the user
// App.jsimportReactfrom'react';import'bootstrap/dist/css/bootstrap.css';import'./App.css';import{Route,Redirect}from'react-router-dom';importProjectsfrom'./components/Projects';importNavbarfrom'./components/Navbar';importProjectDetailsfrom'./components/ProjectDetails';importTaskDetailsfrom'./components/TaskDetails';importSignupfrom'./components/Signup';classAppextendsReact.Component{state={user: this.props.user}setUser=user=>{this.setState({user: user})}render(){return(<divclassName='App'><Navbaruser={this.state.user}setUser={this.setUser}/><Routeexactpath='/projects'render={props=>{if(this.state.user)return<Projects{...props}/>elsereturn<Redirectto='/'/>}}/><Routeexactpath='/projects/:id'render={props=><ProjectDetails{...props}user={this.state.user}/>}/><Routeexactpath='/tasks/:id'component={TaskDetails}/><Routeexactpath='/signup'// to the Signup we have to pass a reference to the setUser method// this we cannot do via component={<some component>}// For this we use the render prop - The term “render prop” refers to a technique for sharing // code between React components using a prop whose value is a function.// A component with a render prop takes a function that returns a React element and calls it // instead of implementing its own render logic.render={props=><SignupsetUser={this.setUser}{...props}/>}/></div>);}}exportdefaultApp;
Now we can use the logged in user in the ProjectDetails component to check if the user is allowed to delete the project.
// components/ProjectDetails.jsrender(){if(this.state.error)return<div>{this.state.error}</div>if(!this.state.project)return(<></>)// we set a boolean if there is a loggedInUser and the user is also the owner of the projectletallowedToDelete=false;constuser=this.props.user;constowner=this.state.project.owner;if(user&&user._id===owner)allowedToDelete=true;return(<div><h1>{this.state.project.title}</h1><p>{this.state.project.description}</p>
// then we only show the button if the the deletion is allowed
{allowedToDelete&&(<Buttonvariant="danger"onClick={this.deleteProject}>
Delete project
</Button>)}
Bonus
If we want to protect a route we can do it like this
// App.js<Routeexactpath='/projects'// instead of component={Projects} we use a render props and an if else statementrender={props=>{if(this.state.user)return<Projects{...props}/>elsereturn<Redirectto='/'/>}}/>
We can create a custom component to protect a route.
// components/ProtectedRouteimportReactfrom'react';import{Route,Redirect}from'react-router-dom';// here we destructure the props - we rename the component prop by using the colonconstProtectedRoute=({component: Component,
user,
path,
redirectPath ='/',
...rest})=>{return(<Routepath={path}render={props=>{returnuser ? (<Component{...props}{...rest}user={user}/>) : (<Redirectto={redirectPath}/>);}}/>);};exportdefaultProtectedRoute;
And use it in App.js
// components/App.jsimportProtectedRoutefrom'./components/ProtectedRoute';// <ProtectedRouteexactpath='/projects'// this is an additional prop that is taken care of with ...restfoo='bar'user={this.state.user}component={Projects}/>//