Ottieni maggiore controllo sulla logica di autenticazione dell'app Next.js tramite l'implementazione personalizzata dell'autenticazione basata su JWT.
L'autenticazione dei token è una strategia popolare utilizzata per proteggere le applicazioni Web e mobili da accessi non autorizzati. In Next.js, puoi utilizzare le funzionalità di autenticazione fornite da Next-auth.
In alternativa, puoi scegliere di sviluppare un sistema di autenticazione personalizzato basato su token utilizzando JSON Web Token (JWT). In questo modo ti assicuri di avere un maggiore controllo sulla logica di autenticazione; essenzialmente, personalizzando il sistema per soddisfare esattamente i requisiti del tuo progetto.
Configura un progetto Next.js
Per iniziare, installa Next.js eseguendo il comando seguente sul tuo terminale.
npx create-next-app@latest next-auth-jwt --experimental-app
Questa guida utilizzerà Next.js 13 che include la directory dell'app.
Successivamente, installa queste dipendenze nel tuo progetto utilizzando npm, il gestore dei pacchetti del nodo.
npm install jose universal-cookie
José è un modulo JavaScript che fornisce una serie di utilità per lavorare con i token Web JSON mentre cookie-universale La dipendenza fornisce un modo semplice per lavorare con i cookie del browser sia negli ambienti lato client che in quelli lato server.
Puoi trovare il codice di questo progetto in questo Repositorio GitHub.
Creare l'interfaccia utente del modulo di accesso
Apri il src/app directory, creare una nuova cartella e darle un nome login. All'interno di questa cartella, aggiungine una nuova pagina.js file e includere il codice seguente.
"use client";
import { useRouter } from"next/navigation";
exportdefaultfunctionLoginPage() {
return (
Il codice sopra crea un componente funzionale della pagina di accesso che renderà un semplice modulo di accesso nel browser per consentire agli utenti di inserire un nome utente e una password.
IL utilizzare il cliente nel codice garantisce che venga dichiarato un confine tra il codice solo server e quello solo client nel file app directory.
In questo caso viene utilizzato per dichiarare che il codice nella pagina di login, in particolare il file handleSubmitla funzione viene eseguita solo sul client; in caso contrario, Next.js genererà un errore.
Ora definiamo il codice per il file handleSubmit funzione. All'interno del componente funzionale, aggiungi il seguente codice.
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");
}
};
Per gestire la logica di autenticazione del login, questa funzione cattura le credenziali dell'utente dal form di login. Invia quindi una richiesta POST a un endpoint API trasmettendo i dettagli dell'utente per la verifica.
Se le credenziali sono valide, indicando che il processo di accesso ha avuto esito positivo: l'API restituisce uno stato di successo nella risposta. La funzione del gestore utilizzerà quindi il router di Next.js per indirizzare l'utente verso un URL specificato, in questo caso il file protetto itinerario.
Definire l'endpoint API di accesso
Dentro il src/app directory, crea una nuova cartella e assegnagli un nome API. All'interno di questa cartella, aggiungine una nuova login/route.js file e includere il codice seguente.
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 });
}
Il compito principale di questa API è verificare le credenziali di accesso passate nelle richieste POST utilizzando dati fittizi.
Una volta verificata con successo, genera un token JWT crittografato associato ai dettagli dell'utente autenticato. Infine, invia una risposta positiva al client, includendo il token nei cookie di risposta; in caso contrario, restituisce una risposta sullo stato di errore.
Implementare la logica di verifica dei token
Il passaggio iniziale nell'autenticazione del token è la generazione del token dopo un processo di accesso riuscito. Il passaggio successivo consiste nell'implementare la logica per la verifica del token.
In sostanza, utilizzerai il file jwtVerifica funzione fornita da José modulo per verificare i token JWT passati con le successive richieste HTTP.
Nel src directory, creane una nuova libs/auth.js file e includere il codice seguente.
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;
}
}
La chiave segreta viene utilizzata per firmare e verificare i token. Confrontando la firma del token decodificato con la firma prevista, il server può effettivamente verificare che il token fornito sia valido e, infine, autorizzare le richieste degli utenti.
Creare .env file nella directory root e aggiungi una chiave segreta univoca come segue:
NEXT_PUBLIC_JWT_SECRET_KEY=your_secret_key
Crea un percorso protetto
Ora devi creare un percorso a cui solo gli utenti autenticati possono accedere. Per fare ciò, creane uno nuovo protetto/pagina.js file nel src/app directory. All'interno di questo file, aggiungi il seguente codice.
exportdefaultfunctionProtectedPage() {
return<h1>Very protected pageh1>;
}
Crea un hook per gestire lo stato di autenticazione
Crea una nuova cartella nel file src directory e nominarla ganci. All'interno di questa cartella aggiungine uno nuovo useAuth/index.js file e includere il codice seguente.
"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;
}
Questo hook gestisce lo stato di autenticazione sul lato client. Recupera e verifica la validità del token JWT presente nei cookie utilizzando il file verificareJwtToken funzione, quindi imposta i dettagli dell'utente autenticato su aut stato.
In questo modo, consente ad altri componenti di accedere e utilizzare le informazioni dell'utente autenticato. Ciò è essenziale per scenari come la realizzazione di aggiornamenti dell'interfaccia utente in base allo stato di autenticazione, l'esecuzione di richieste API successive o il rendering di contenuti diversi in base ai ruoli utente.
In questo caso, utilizzerai l'hook per eseguire il rendering di contenuti diversi sul file casa percorso in base allo stato di autenticazione di un utente.
Un approccio alternativo che potresti prendere in considerazione è la gestione gestione dello stato utilizzando Redux Toolkit o impiegando a strumento di gestione dello stato come Jotai. Questo approccio garantisce che i componenti possano ottenere l'accesso globale allo stato di autenticazione o a qualsiasi altro stato definito.
Vai avanti e apri il file app/pagina.js file, elimina il codice boilerplate Next.js e aggiungi il seguente codice.
"use client" ;
import { useAuth } from"@/hooks/useAuth";
import Link from"next/link";
exportdefaultfunctionHome() {
const auth = useAuth();
return<>Public Home Page</h1>
Il codice sopra utilizza il file utilizzareAuth hook per gestire lo stato di autenticazione. In tal modo, rende condizionatamente una home page pubblica con un collegamento al file login percorso della pagina quando l'utente non è autenticato e visualizza un paragrafo per un utente autenticato.
Aggiungi un middleware per imporre l'accesso autorizzato ai percorsi protetti
Nel src directory, creane una nuova middleware.js file e aggiungi il codice qui sotto.
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*"] };
Questo codice middleware funge da guardia. Controlla per garantire che quando gli utenti desiderano accedere alle pagine protette, siano autenticati e autorizzati ad accedere ai percorsi, oltre a reindirizzare gli utenti non autorizzati alla pagina di accesso.
Protezione delle applicazioni Next.js
L'autenticazione tramite token è un meccanismo di sicurezza efficace. Tuttavia, non è l'unica strategia disponibile per proteggere le tue applicazioni da accessi non autorizzati.
Per rafforzare le applicazioni rispetto al panorama dinamico della sicurezza informatica, è importante adottare una sicurezza completa approccio che affronta in modo olistico potenziali lacune e vulnerabilità nella sicurezza per garantire una protezione approfondita protezione.