Питання авторизації та захищених маршрутів в React.js є актуальним для багатьох розробників. Забезпечення доступу до різних частин додатку в залежності від ролі користувача вимагає вдосконалених рішень. У цій статті ми розглянемо практичний підхід до вирішення цього завдання з використанням React.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
App.jsx import { createBrowserRouter, RouterProvider } from "react-router-dom"; import RootLayout from "./root/RootLayout"; import Home from "./pages/Home"; import Error from "./Error/Error"; import ContactUs from "./pages/ContactUs.jsx"; import NewLogin from "./pages/NewLogin.jsx"; import { loader as tokenLoader } from "./util/auth.js"; import { action as authAction } from "./pages/NewLogin.jsx"; import { action as logoutAction } from "./pages/Logout.js"; import Nutrition from "./health/Nutrition.jsx"; import HealthAwareness from "./health/HealthAwareness.jsx"; const router = createBrowserRouter([ { path: "/", element: <RootLayout />, errorElement: <Error />, id: "root", loader: tokenLoader, children: [ { path: "", element: <Home /> }, { path: "health-awareness", element: <HealthAwareness /> }, { path: "ca", element: <Nutrition /> }, { path: "contact-us", element: <ContactUs /> }, { path: "logout", action: logoutAction }, ], }, { path: "login", element: <NewLogin />, action: authAction }, ]); export default function App() { return <RouterProvider router={router} />; } RootLayout.jsx import { Outlet } from "react-router-dom"; import NewNavbar from "../components/NewNavbar.jsx"; export default function RootLayout() { return ( <> <NewNavbar /> <main> <Outlet /> </main> </> ); } Authentication handling is in NewLogin.jsx import { json, redirect } from "react-router-dom"; import LoginForm from "../components/LoginForm"; export async function action({ request }) { const data = await request.formData(); const authData = { username: data.get("username"), password: data.get("password"), }; const response = await fetch("http://localhost:3000/auth/login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(authData), }); if (response.status === 400) { return response; //throw json({ message: "invalid data" }, { status: 400 }); } if (!response.ok) { throw json( { message: "Could not authenticate this user." }, { status: 400 } ); } const resData = await response.json(); const token = resData.token; localStorage.setItem("token", token); console.log(token); return redirect("/"); } auth.js export function getAuthToken() { const token = localStorage.getItem('token'); return token; } export function loader() { return getAuthToken(); } Logout.js import { redirect } from "react-router-dom"; export function action() { localStorage.removeItem('token'); return redirect('/'); } NewNavbar.jsx function logoutHandler() { const proceed = window.confirm("Are you sure؟"); if (proceed) { submit(null, { action: "/logout", method: "post" }); } } const token = useRouteLoaderData("root"); //inside the navbar {!token && ( <li className={`hidden md:block list-none text-[23px] p-6 hover:animate-pulse ${ isScrolled ? "text-emerald-800" : "text-slate-100" }`} > <NavLink to="/login">login</NavLink> </li> )} {token && ( <li className={`hidden md:block list-none text-[23px] hover:animate-pulse p-6 ${ isScrolled ? "text-emerald-800" : "text-slate-100" }`} > <Form action="/logout" method="post"> <button onClick={logoutHandler}>logout</button> </Form> </li> )} |