Få mer kontroll over autentiseringslogikken til Next.js-appen din gjennom tilpasset JWT-basert autentiseringsimplementering.
Token-autentisering er en populær strategi som brukes for å beskytte nett- og mobilapplikasjoner mot uautorisert tilgang. I Next.js kan du bruke autentiseringsfunksjonene levert av Next-auth.
Alternativt kan du velge å utvikle et tilpasset token-basert autentiseringssystem ved å bruke JSON Web Tokens (JWTs). Ved å gjøre det sikrer du at du har mer kontroll over autentiseringslogikken; i hovedsak tilpasse systemet til nøyaktig å matche kravene til prosjektet ditt.
Sett opp et Next.js-prosjekt
For å komme i gang, installer Next.js ved å kjøre kommandoen nedenfor på terminalen din.
npx create-next-app@latest next-auth-jwt --experimental-app
Denne guiden vil bruke Next.js 13 som inkluderer appkatalogen.
Deretter installerer du disse avhengighetene i prosjektet ditt ved å bruke npm, Node Package Manager.
npm install jose universal-cookie
Jose er en JavaScript-modul som gir et sett med verktøy for å jobbe med JSON Web Tokens mens
universal-informasjonskapsel avhengighet gir en enkel måte å jobbe med nettleserinformasjonskapsler i både klient- og server-sidemiljøer.Du finner dette prosjektets kode i denne GitHub-depot.
Opprett brukergrensesnittet for påloggingsskjemaet
Åpne src/app katalog, opprett en ny mappe og navngi den Logg Inn. Legg til en ny i denne mappen side.js fil og ta med koden nedenfor.
"use client";
import { useRouter } from"next/navigation";
exportdefaultfunctionLoginPage() {
return (
Koden ovenfor oppretter en funksjonskomponent for påloggingssiden som vil gjengi et enkelt påloggingsskjema på nettleseren slik at brukere kan skrive inn et brukernavn og et passord.
De bruke klient setningen i koden sikrer at en grense er deklarert mellom server-bare og klient-bare kode i app katalog.
I dette tilfellet brukes den til å erklære at koden på påloggingssiden, spesielt handleSend innfunksjonen utføres kun på klienten; ellers vil Next.js gi en feilmelding.
La oss nå definere koden for handleSend inn funksjon. Inne i den funksjonelle komponenten legger du til følgende kode.
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");
}
};
For å administrere påloggingsautentiseringslogikken fanger denne funksjonen opp brukerlegitimasjonen fra påloggingsskjemaet. Den sender deretter en POST-forespørsel til et API-endepunkt som sender brukerdetaljene for verifisering.
Hvis legitimasjonen er gyldig, noe som indikerer at påloggingsprosessen var vellykket – API-en returnerer en suksessstatus i svaret. Behandlerfunksjonen vil da bruke Next.js sin ruter til å navigere brukeren til en spesifisert URL, i dette tilfellet beskyttet rute.
Definer Login API Endpoint
Inne i src/app katalog, opprett en ny mappe og navngi den api. Legg til en ny i denne mappen login/route.js fil og ta med koden nedenfor.
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 });
}
Den primære oppgaven for denne APIen er å verifisere påloggingslegitimasjonen som sendes i POST-forespørslene ved hjelp av falske data.
Etter vellykket verifisering genererer den et kryptert JWT-token knyttet til de autentiserte brukerdetaljene. Til slutt sender den et vellykket svar til klienten, inkludert token i responsinformasjonskapslene; ellers returnerer den et feilstatussvar.
Implementer Token Verification Logic
Det første trinnet i token-autentisering er å generere tokenet etter en vellykket påloggingsprosess. Det neste trinnet er å implementere logikken for tokenverifisering.
I hovedsak vil du bruke jwtBekreft funksjon levert av Jose modul for å verifisere JWT-tokenene som ble sendt med påfølgende HTTP-forespørsler.
I src katalog, opprette en ny libs/auth.js fil og ta med koden nedenfor.
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;
}
}
Den hemmelige nøkkelen brukes til å signere og bekrefte tokens. Ved å sammenligne den dekodede tokensignaturen med den forventede signaturen, kan serveren effektivt verifisere at det angitte tokenet er gyldig, og til slutt autorisere brukernes forespørsler.
Skape .env fil i rotkatalogen og legg til en unik hemmelig nøkkel som følger:
NEXT_PUBLIC_JWT_SECRET_KEY=your_secret_key
Lag en beskyttet rute
Nå må du opprette en rute som bare autentiserte brukere kan få tilgang til. For å gjøre det, opprette en ny protected/page.js fil i src/app katalog. Inni denne filen legger du til følgende kode.
exportdefaultfunctionProtectedPage() {
return<h1>Very protected pageh1>;
}
Opprett en krok for å administrere autentiseringstilstanden
Opprett en ny mappe i src katalog og navngi den kroker. Legg til en ny i denne mappen useAuth/index.js fil og ta med koden nedenfor.
"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;
}
Denne kroken administrerer autentiseringstilstanden på klientsiden. Den henter og verifiserer gyldigheten til JWT-tokenet som finnes i informasjonskapsler ved hjelp av verifyJwtToken funksjon, og setter deretter de autentiserte brukerdetaljene til auth stat.
Ved å gjøre det lar det andre komponenter få tilgang til og bruke den autentiserte brukerens informasjon. Dette er viktig for scenarier som å lage UI-oppdateringer basert på autentiseringsstatus, lage påfølgende API-forespørsler eller gjengi forskjellig innhold basert på brukerroller.
I dette tilfellet vil du bruke kroken til å gjengi forskjellig innhold på hjem rute basert på autentiseringstilstanden til en bruker.
En alternativ tilnærming du kan vurdere er håndtering statsadministrasjon ved hjelp av Redux Toolkit eller ansette en statlig styringsverktøy som Jotai. Denne tilnærmingen garanterer at komponenter kan få global tilgang til autentiseringstilstanden eller en hvilken som helst annen definert tilstand.
Gå videre og åpne app/page.js fil, slett boilerplate Next.js-koden, og legg til følgende kode.
"use client" ;
import { useAuth } from"@/hooks/useAuth";
import Link from"next/link";
exportdefaultfunctionHome() {
const auth = useAuth();
return<>Public Home Page</h1>
Koden ovenfor bruker brukAuth krok for å administrere autentiseringstilstanden. Ved å gjøre det, gjengir den betinget en offentlig hjemmeside med en lenke til Logg Inn siderute når brukeren ikke er autentisert, og viser et avsnitt for en autentisert bruker.
Legg til en mellomvare for å håndheve autorisert tilgang til beskyttede ruter
I src katalog, opprette en ny middleware.js fil, og legg til koden nedenfor.
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*"] };
Denne mellomvarekoden fungerer som en vakt. Den sjekker for å sikre at når brukere ønsker å få tilgang til beskyttede sider, er de autentisert og autorisert til å få tilgang til rutene, i tillegg til å omdirigere uautoriserte brukere til påloggingssiden.
Sikring av Next.js-applikasjoner
Token-autentisering er en effektiv sikkerhetsmekanisme. Det er imidlertid ikke den eneste tilgjengelige strategien for å beskytte applikasjonene dine mot uautorisert tilgang.
For å styrke applikasjoner mot det dynamiske cybersikkerhetslandskapet, er det viktig å ta i bruk en omfattende sikkerhet tilnærming som helhetlig adresserer potensielle sikkerhetshull og sårbarheter for å garantere grundig beskyttelse.