Krijg meer controle over de authenticatielogica van uw Next.js-app via aangepaste, op JWT gebaseerde authenticatie-implementatie.

Tokenauthenticatie is een populaire strategie die wordt gebruikt om web- en mobiele applicaties te beschermen tegen ongeautoriseerde toegang. In Next.js kunt u de authenticatiefuncties van Next-auth gebruiken.

Als alternatief kunt u ervoor kiezen om een ​​aangepast, op tokens gebaseerd authenticatiesysteem te ontwikkelen met behulp van JSON Web Tokens (JWT's). Door dit te doen zorg je ervoor dat je meer controle hebt over de authenticatielogica; Kortom, het aanpassen van het systeem zodat het precies aansluit bij de vereisten van uw project.

Zet een Next.js-project op

Om aan de slag te gaan, installeert u Next.js door de onderstaande opdracht op uw terminal uit te voeren.

npx create-next-app@latest next-auth-jwt --experimental-app

Deze gids zal gebruiken Next.js 13 die de app-map bevat.

Installeer vervolgens deze afhankelijkheden in uw project met behulp van npm, de knooppuntpakketbeheerder.

instagram viewer
npm install jose universal-cookie

Jose is een JavaScript-module die een reeks hulpprogramma's biedt voor het werken met JSON-webtokens terwijl de universeel koekje afhankelijkheid biedt een eenvoudige manier om met browsercookies te werken in zowel de client- als de serveromgeving.

U kunt de code van dit project hierin vinden GitHub-opslagplaats.

Maak de gebruikersinterface van het inlogformulier

Open de src/app directory, maak een nieuwe map en geef deze een naam Log in. Voeg in deze map een nieuw pagina.js bestand en voeg de onderstaande code toe.

"use client";
import { useRouter } from"next/navigation";

exportdefaultfunctionLoginPage() {
return (


De bovenstaande code creëert een functionele component voor een inlogpagina die een eenvoudig inlogformulier in de browser zal weergeven, zodat gebruikers een gebruikersnaam en een wachtwoord kunnen invoeren.

De gebruik cliënt -instructie in de code zorgt ervoor dat er een grens wordt aangegeven tussen alleen server- en client-only code in de app map.

In dit geval wordt het gebruikt om aan te geven dat de code op de inlogpagina, met name de handvatVerzendenfunctie wordt alleen uitgevoerd op de client; anders zal Next.js een fout genereren.

Laten we nu de code voor de handvatVerzenden functie. Voeg binnen de functionele component de volgende code toe.

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");
}
 };

Om de logica van de login-authenticatie te beheren, legt deze functie de gebruikersreferenties van het login-formulier vast. Vervolgens stuurt het een POST-verzoek naar een API-eindpunt, waarbij de gebruikersgegevens ter verificatie worden doorgegeven.

Als de inloggegevens geldig zijn, wat aangeeft dat het aanmeldingsproces succesvol was, retourneert de API een successtatus in het antwoord. De handlerfunctie gebruikt vervolgens de router van Next.js om de gebruiker naar een opgegeven URL te navigeren, in dit geval de beschermd route.

Definieer het Login API-eindpunt

Binnen in de src/app directory, maak een nieuwe map en geef deze een naam api. Voeg in deze map een nieuw login/route.js bestand en voeg de onderstaande code toe.

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 });
}

De primaire taak van deze API is het verifiëren van de inloggegevens die zijn doorgegeven in de POST-aanvragen met behulp van nepgegevens.

Na succesvolle verificatie genereert het een gecodeerd JWT-token dat is gekoppeld aan de geverifieerde gebruikersgegevens. Ten slotte stuurt het een succesvol antwoord naar de klant, inclusief het token in de responscookies; anders retourneert het een foutstatusreactie.

Implementeer tokenverificatielogica

De eerste stap bij tokenauthenticatie is het genereren van het token na een succesvol inlogproces. De volgende stap is het implementeren van de logica voor tokenverificatie.

In principe zul je gebruik maken van de jwtVerifieer functie geleverd door de Jose module om de JWT-tokens te verifiëren die zijn doorgegeven met daaropvolgende HTTP-verzoeken.

In de src map, maak een nieuwe libs/auth.js bestand en voeg de onderstaande code toe.

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;
}
}

De geheime sleutel wordt gebruikt bij het ondertekenen en verifiëren van de tokens. Door de gedecodeerde tokenhandtekening te vergelijken met de verwachte handtekening, kan de server effectief verifiëren dat het verstrekte token geldig is, en uiteindelijk de verzoeken van de gebruikers autoriseren.

Creëren .env bestand in de hoofdmap en voeg als volgt een unieke geheime sleutel toe:

NEXT_PUBLIC_JWT_SECRET_KEY=your_secret_key

Maak een beveiligde route

Nu moet u een route maken waartoe alleen geverifieerde gebruikers toegang kunnen krijgen. Maak hiervoor een nieuw beschermd/pagina.js bestand in de src/app map. Voeg in dit bestand de volgende code toe.

exportdefaultfunctionProtectedPage() {
return<h1>Very protected pageh1>;
}

Maak een hook om de authenticatiestatus te beheren

Maak een nieuwe map in de src map en geef deze een naam haken. Voeg in deze map een nieuw gebruikAuth/index.js bestand en voeg de onderstaande code toe.

"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;
}

Deze hook beheert de authenticatiestatus aan de clientzijde. Het haalt en verifieert de geldigheid van het JWT-token dat aanwezig is in cookies met behulp van de verifieerJwtToken functie en stelt vervolgens de geverifieerde gebruikersgegevens in op de auth staat.

Door dit te doen, kunnen andere componenten toegang krijgen tot de gegevens van de geverifieerde gebruiker en deze gebruiken. Dit is essentieel voor scenario's zoals het maken van UI-updates op basis van de authenticatiestatus, het doen van daaropvolgende API-verzoeken of het weergeven van verschillende inhoud op basis van gebruikersrollen.

In dit geval gebruik je de hook om verschillende inhoud op het thuis route gebaseerd op de authenticatiestatus van een gebruiker.

Een alternatieve aanpak die u zou kunnen overwegen, is handling statusbeheer met behulp van Redux Toolkit of het inzetten van een staatsbeheertool zoals Jotai. Deze aanpak garandeert dat componenten globale toegang kunnen krijgen tot de authenticatiestatus of een andere gedefinieerde status.

Ga je gang en open de app/pagina.js bestand, verwijder de standaard Next.js-code en voeg de volgende code toe.

"use client" ;

import { useAuth } from"@/hooks/useAuth";
import Link from"next/link";
exportdefaultfunctionHome() {
const auth = useAuth();
return<>

Public Home Page</h1>

De bovenstaande code maakt gebruik van de gebruikAuth hook om de authenticatiestatus te beheren. Daarbij wordt voorwaardelijk een openbare startpagina weergegeven met een link naar de Log in paginaroute wanneer de gebruiker niet is geverifieerd, en geeft een alinea weer voor een geverifieerde gebruiker.

Voeg een middleware toe om geautoriseerde toegang tot beschermde routes af te dwingen

In de src map, maak een nieuwe middleware.js bestand en voeg de onderstaande code toe.

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*"] };

Deze middlewarecode fungeert als bewaker. Het controleert of wanneer gebruikers toegang willen krijgen tot beveiligde pagina's, ze worden geverifieerd en geautoriseerd voor toegang tot de routes, en ongeautoriseerde gebruikers worden omgeleid naar de inlogpagina.

Next.js-applicaties beveiligen

Tokenauthenticatie is een effectief beveiligingsmechanisme. Het is echter niet de enige beschikbare strategie om uw applicaties te beschermen tegen ongeautoriseerde toegang.

Om applicaties te beschermen tegen het dynamische cybersecuritylandschap, is het belangrijk om een ​​alomvattende beveiliging te implementeren aanpak die op holistische wijze mogelijke mazen in de beveiliging en kwetsbaarheden aanpakt om een ​​grondige aanpak te garanderen bescherming.