Získejte větší kontrolu nad logikou ověřování vaší aplikace Next.js díky vlastní implementaci ověřování založené na JWT.
Tokenová autentizace je oblíbená strategie používaná při ochraně webových a mobilních aplikací před neoprávněným přístupem. V Next.js můžete využít autentizační funkce poskytované Next-auth.
Případně se můžete rozhodnout vyvinout vlastní ověřovací systém založený na tokenech pomocí webových tokenů JSON (JWT). Tím zajistíte, že budete mít větší kontrolu nad logikou ověřování; v podstatě přizpůsobení systému tak, aby přesně odpovídal požadavkům vašeho projektu.
Nastavte projekt Next.js
Chcete-li začít, nainstalujte Next.js spuštěním příkazu níže na vašem terminálu.
npx create-next-app@latest next-auth-jwt --experimental-app
Tento návod využije Next.js 13, který obsahuje adresář aplikace.
Dále nainstalujte tyto závislosti do svého projektu pomocí npm, Správce balíčků uzlů.
npm install jose universal-cookie
Jose je modul JavaScriptu, který poskytuje sadu nástrojů pro práci s webovými tokeny JSON, zatímco
univerzální soubor cookie závislost poskytuje jednoduchý způsob práce se soubory cookie prohlížeče v prostředí na straně klienta i na straně serveru.Zde najdete kód tohoto projektu úložiště GitHub.
Vytvořte uživatelské rozhraní přihlašovacího formuláře
Otevři src/app adresář, vytvořte novou složku a pojmenujte ji přihlásit se. Do této složky přidejte nový page.js soubor a zahrňte níže uvedený kód.
"use client";
import { useRouter } from"next/navigation";
exportdefaultfunctionLoginPage() {
return (
Výše uvedený kód vytvoří funkční komponentu přihlašovací stránky, která v prohlížeči vykreslí jednoduchý přihlašovací formulář, který uživatelům umožní zadat uživatelské jméno a heslo.
The používat klienta příkaz v kódu zajišťuje, že je deklarována hranice mezi kódem pouze pro server a pouze pro klienta v aplikace adresář.
V tomto případě se používá k deklaraci, že kód na přihlašovací stránce, zejména handleSubmitfunkce se provádí pouze na klientovi; jinak Next.js vyvolá chybu.
Nyní definujme kód pro handleSubmit funkce. Do funkční součásti přidejte následující kód.
const router = useRouter();
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const username = formData.get("username");
const password = formData.get("password");
const res = await fetch("/api/login", {
method: "POST",
body: JSON.stringify({ username, password }),
});
const { success } = await res.json();
if (success) {
router.push("/protected");
router.refresh();
} else {
alert("Login failed");
}
};
Pro správu logiky ověřování přihlášení tato funkce zachycuje přihlašovací údaje uživatele z přihlašovacího formuláře. Poté odešle požadavek POST na koncový bod API, který předá údaje o uživateli k ověření.
Pokud jsou pověření platná, což znamená, že proces přihlášení byl úspěšný – rozhraní API vrátí v odpovědi stav úspěchu. Funkce handleru pak použije router Next.js k navigaci uživatele na zadanou URL, v tomto případě chráněný trasa.
Definujte koncový bod Login API
Uvnitř src/app adresář, vytvořte novou složku a pojmenujte ji api. Do této složky přidejte nový login/route.js soubor a zahrňte níže uvedený kód.
import { SignJWT } from"jose";
import { NextResponse } from"next/server";
import { getJwtSecretKey } from"@/libs/auth";
exportasyncfunctionPOST(request) {
const body = await request.json();
if (body.username "admin" && body.password "admin") {
const token = awaitnew SignJWT({
username: body.username,
})
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("30s")
.sign(getJwtSecretKey());
const response = NextResponse.json(
{ success: true },
{ status: 200, headers: { "content-type": "application/json" } }
);
response.cookies.set({
name: "token",
value: token,
path: "/",
});
return response;
}
return NextResponse.json({ success: false });
}
Primárním úkolem tohoto rozhraní API je ověření přihlašovacích údajů předávaných v požadavcích POST pomocí falešných dat.
Po úspěšném ověření vygeneruje zašifrovaný token JWT spojený s podrobnostmi ověřeného uživatele. Nakonec odešle klientovi úspěšnou odpověď, včetně tokenu v souborech cookie odpovědi; jinak vrátí odpověď na stav selhání.
Implementujte logiku ověření tokenu
Prvním krokem v autentizaci tokenu je vygenerování tokenu po úspěšném přihlášení. Dalším krokem je implementace logiky pro ověření tokenu.
V podstatě budete používat jwtVerify funkce, kterou poskytuje Jose modul pro ověření předávaných tokenů JWT s následnými požadavky HTTP.
V src adresář, vytvořte nový libs/auth.js soubor a zahrňte níže uvedený kód.
import { jwtVerify } from"jose";
exportfunctiongetJwtSecretKey() {
const secret = process.env.NEXT_PUBLIC_JWT_SECRET_KEY;
if (!secret) {
thrownewError("JWT Secret key is not matched");
}
returnnew TextEncoder().encode(secret);
}
exportasyncfunctionverifyJwtToken(token) {
try {
const { payload } = await jwtVerify(token, getJwtSecretKey());
return payload;
} catch (error) {
returnnull;
}
}
Tajný klíč se používá při podepisování a ověřování tokenů. Porovnáním dekódovaného podpisu tokenu s očekávaným podpisem může server efektivně ověřit, zda je poskytnutý token platný, a nakonec autorizovat požadavky uživatelů.
Vytvořit .env soubor v kořenovém adresáři a přidejte jedinečný tajný klíč následovně:
NEXT_PUBLIC_JWT_SECRET_KEY=your_secret_key
Vytvořte chráněnou trasu
Nyní musíte vytvořit trasu, ke které budou mít přístup pouze ověření uživatelé. Chcete-li tak učinit, vytvořte nový protected/page.js soubor v src/app adresář. Do tohoto souboru přidejte následující kód.
exportdefaultfunctionProtectedPage() {
return<h1>Very protected pageh1>;
}
Vytvořte Hook pro správu stavu ověřování
Vytvořte novou složku v src adresář a pojmenujte jej háčky. Do této složky přidejte nový useAuth/index.js soubor a zahrňte níže uvedený kód.
"use client" ;
import React from"react";
import Cookies from"universal-cookie";
import { verifyJwtToken } from"@/libs/auth";exportfunctionuseAuth() {
const [auth, setAuth] = React.useState(null);
const getVerifiedtoken = async () => {
const cookies = new Cookies();
const token = cookies.get("token")?? null;
const verifiedToken = await verifyJwtToken(token);
setAuth(verifiedToken);
};
React.useEffect(() => {
getVerifiedtoken();
}, []);
return auth;
}
Tento hák spravuje stav ověřování na straně klienta. Načte a ověří platnost tokenu JWT přítomného v souborech cookie pomocí ověřitJwtToken a poté nastaví podrobnosti ověřeného uživatele na auth Stát.
Tím umožňuje ostatním komponentům přístup k informacím ověřeného uživatele a jejich využití. To je nezbytné pro scénáře, jako je provádění aktualizací uživatelského rozhraní na základě stavu ověření, provádění následných požadavků API nebo vykreslování různého obsahu na základě uživatelských rolí.
V tomto případě použijete háček k vykreslení jiného obsahu na Domov trasa založená na stavu autentizace uživatele.
Alternativní přístup, který byste mohli zvážit, je manipulace řízení stavu pomocí Redux Toolkit nebo zaměstnávat a nástroj řízení státu, jako je Jotai. Tento přístup zaručuje, že komponenty mohou získat globální přístup ke stavu autentizace nebo jinému definovanému stavu.
Pokračujte a otevřete app/page.js soubor, odstraňte standardní kód Next.js a přidejte následující kód.
"use client" ;
import { useAuth } from"@/hooks/useAuth";
import Link from"next/link";
exportdefaultfunctionHome() {
const auth = useAuth();
return<>Public Home Page</h1>
Výše uvedený kód využívá useAuth háček pro správu stavu ověřování. Přitom podmíněně vykreslí veřejnou domovskou stránku s odkazem na přihlásit se směrování stránky, když uživatel není ověřen, a zobrazí odstavec pro ověřeného uživatele.
Přidejte middleware k vynucení autorizovaného přístupu k chráněným trasám
V src adresář, vytvořte nový middleware.js soubor a přidejte kód níže.
import { NextResponse } from"next/server";
import { verifyJwtToken } from"@/libs/auth";const AUTH_PAGES = ["/login"];
const isAuthPages = (url) => AUTH_PAGES.some((page) => page.startsWith(url));
exportasyncfunctionmiddleware(request) {
const { url, nextUrl, cookies } = request;
const { value: token } = cookies.get("token")?? { value: null };
const hasVerifiedToken = token && (await verifyJwtToken(token));
const isAuthPageRequested = isAuthPages(nextUrl.pathname);if (isAuthPageRequested) {
if (!hasVerifiedToken) {
const response = NextResponse.next();
response.cookies.delete("token");
return response;
}
const response = NextResponse.redirect(new URL(`/`, url));
return response;
}if (!hasVerifiedToken) {
const searchParams = new URLSearchParams(nextUrl.searchParams);
searchParams.set("next", nextUrl.pathname);
const response = NextResponse.redirect(
new URL(`/login?${searchParams}`, url)
);
response.cookies.delete("token");
return response;
}return NextResponse.next();
}
exportconst config = { matcher: ["/login", "/protected/:path*"] };
Tento middlewarový kód funguje jako stráž. Kontroluje, že když uživatelé chtějí přistupovat k chráněným stránkám, jsou autentizováni a oprávněni k přístupu k trasám, a navíc přesměrovává neoprávněné uživatele na přihlašovací stránku.
Zabezpečení aplikací Next.js
Autentizace pomocí tokenu je účinný bezpečnostní mechanismus. Není to však jediná dostupná strategie pro ochranu vašich aplikací před neoprávněným přístupem.
Pro posílení aplikací proti dynamickému prostředí kybernetické bezpečnosti je důležité přijmout komplexní zabezpečení přístup, který holisticky řeší potenciální bezpečnostní mezery a zranitelnosti, aby byl zaručen důkladný ochrana.