How can we protect our routes from unauthorized access? Let's learn about it.
Let's start from scratch.
So first create a react app
npx create-react-app your-project-name
Or
yarn create vite your-project-name
I am using yarn vite here
After running the above yarn command, you need to select two things:
- Select framework
- Select variant(language)
After that, open VS Code and run following command:
yarn
yarn add axios
Or
npm install
npm install axios
Then run your app
yarn dev
or
npm start
Now, let's create the login page and home page.
//Login.jsx
import React, { useState } from "react";
import { Button } from "react-bootstrap";
import "./commonStyle.css";
const Login = () => {
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
const handleLogin = () => {
const data = {
username: userName,
pass: password,
};
const dataString = JSON.stringify(data);
sessionStorage.setItem("Status", dataString);
};
return (
<div className="Cont">
<div className="homeCont ">
<h2>Login</h2>
<input
type="text"
className="inputStyle"
value={userName}
onChange={(e) => setUserName(e.target.value)}
placeholder="Enter your username"
/>
<input
type="password"
className="inputStyle"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
/>
<Button
className={password.length < 8 ? "disableBtn" : "btn"}
onClick={handleLogin}
>
Login
</Button>
</div>
</div>
);
};
export default Login;
Along with create Css file
/* commonStyle.css */
.Cont{
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #535C91;
color: #fff;
}
.homeCont{
background-color: #070F2B;
border: 1px solid #1a285b;
height: 40vh;
width: 30vw;
border-radius: 5px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.inputStyle{
width: 80%;
height: 50px;
margin: 10px 0;
background-color: #191859;
border: 1px solid #3a3960;
border-radius: 5px;
color: #fff;
font-size: 15px;
padding: 0 7px;
}
.inputStyle::placeholder{
color: #a7a7a7;
}
.inputStyle:focus{
outline: none;
}
.btn{
background-color: #f61542;
width: 80%;
height: 40px;
margin: 10px 0;
color: #fff;
font-size: 16px;
border: none;
border-radius: 50px;
cursor: pointer;
}
.btn:hover{
background-color: #f61542;
}
.disableBtn{
background-color: #df4d6a;
cursor: default;
}
.disableBtn:hover{
background-color: #df4d6a;
}
.bookCont{
height: auto;
padding-top: 10px;
}
.bookDtl{
height: 30px;
width: 100%;
border: 1px solid #535C91;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 0 8px;
align-items: center;
}
And It's look like this
Now, create the home page that we want to protect so that only authorized users can see it. In my case, users can access the home page only after logging in.
Note: On the Home page, I'm calling an API to add books, but it's up to you what you want to render on this page.
//home.jsx
import React from "react";
import { useEffect, useState } from "react";
import axios from "axios";
import "./commonStyle.css";
const Home = () => {
const [bookData, setBookData] = useState([]);
const [bookTitle, setBookTitle] = useState("");
const [bookAuthor, setBookAuthor] = useState("");
const [msg, setMsg] = useState("");
const handleSubmit = async () => {
const payload = {
title: bookTitle,
author: bookAuthor,
};
axios
.post("http://localhost:3001/books", payload)
.then((res) => {
setMsg(res.data.message);
fetchData();
})
.catch(() => {
setMsg("Something went wrong");
});
};
const fetchData = async () => {
try {
const response = await axios.get("http://localhost:3001/books");
setBookData(response.data.data);
} catch (error) {
console.error("Error fetching data:", error);
}
};
useEffect(() => {
fetchData();
}, []);
return (
<div className="Cont">
<div className="homeCont bookCont">
<h3>Book Details</h3>
<input
className="inputStyle"
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
placeholder="Book Title"
value={bookTitle}
onChange={(e) => setBookTitle(e.target.value)}
autoComplete="off"
/>
<input
className="inputStyle"
placeholder="Book Author"
value={bookAuthor}
autoComplete="off"
onCopy={(e) => e.preventDefault()}
onPaste={(e) => e.preventDefault()}
onChange={(e) => setBookAuthor(e.target.value)}
/>
<p>{msg}</p>
<button className="btn" onClick={handleSubmit}>
Add Book
</button>
{bookData.map((book) => {
return (
<div className="bookDtl" key={book.id}>
<p> {book.id}</p>
<p>{book.title}</p>
<p>{book.author}</p>
</div>
);
})}
</div>
</div>
);
};
export default Home;
Now come our main page App.jsx
//App.jsx
import './App.css'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Home from './Screens/Home'
import PrivateRoute from './Screens/PrivateRoute'
import Login from './Screens/Login'
function App() {
return (
<Router>
<Routes>
<Route path='/' element={<Login />} exact />
<Route element={<PrivateRoute />}>
<Route path='/home' element={<Home />} />
</Route>
</Routes>
</Router>
)
}
export default App
Here, I have created a simple route using the react-router-dom library. Additionally, I have defined my private routes inside this setup
<Route element={<PrivateRoute />}> </Route>
So here, I am protecting only one route, i.e., the home route, but you can protect as many as you want.
After that, create the Private Route page, which we are importing on the App page.
//PrivateRoute.jsx
import React from 'react'
import { Navigate, Outlet } from 'react-router-dom'
const PrivateRoute = ({ children, ...rest }) => {
const data = sessionStorage.getItem('Status');
const isLogin = JSON.parse(data);
return (
isLogin ?
<Outlet />
:
<Navigate to='/' />
)
}
export default PrivateRoute
- We're using the ...rest parameter in the PrivateRoute component's props. This allows the component to accept any additional props that are not explicitly destructured (children in this case).
- The rest props are then passed down to the underlying component using the spread operator (...rest).
- This flexibility allows you to configure the route further by passing props such as exact, path, component, render, or any custom props you may need directly to the component within PrivateRoute. e.g.
<PrivateRoute path="/about" element={<About />} exact />
"Here, I check if the user is logged in, then create an object inside the sessionStorage and check this during private route. If login data is available in sessionStorage, then the user can go to the home page; otherwise, the user can't go to the home page.
An should be used in parent route elements to render their child route elements. This allows nested UI to show up when child routes are rendered. If the parent route matched exactly, it will render a child index route or nothing if there is no index route.
*Thank you ❤️ *
Top comments (0)