Имайте повече контрол върху логиката за удостоверяване на вашето приложение Next.js чрез персонализирано внедряване на базирано на JWT удостоверяване.
Удостоверяването с токени е популярна стратегия, използвана за защита на уеб и мобилни приложения от неоторизиран достъп. В Next.js можете да използвате функциите за удостоверяване, предоставени от Next-auth.
Като алтернатива можете да изберете да разработите персонализирана система за удостоверяване, базирана на токени, като използвате JSON уеб токени (JWT). По този начин вие гарантирате, че имате повече контрол върху логиката за удостоверяване; по същество, персонализиране на системата, за да отговаря точно на изискванията на вашия проект.
Настройте проект Next.js
За да започнете, инсталирайте Next.js, като изпълните командата по-долу на вашия терминал.
npx create-next-app@latest next-auth-jwt --experimental-app
Това ръководство ще използва Next.js 13, който включва директорията на приложението.
След това инсталирайте тези зависимости във вашия проект, като използвате npm, мениджърът на пакети на възли.
npm install jose universal-cookie
Хосе е JavaScript модул, който предоставя набор от помощни програми за работа с JSON уеб токени, докато универсална бисквитка dependency предоставя лесен начин за работа с бисквитки на браузъра както в клиентската, така и в сървърната среда.
Можете да намерите кода на този проект тук GitHub хранилище.
Създайте потребителския интерфейс на формата за вход
Отвори src/приложение директория, създайте нова папка и я наименувайте Влизам. В тази папка добавете нова page.js файл и включете кода по-долу.
"use client";
import { useRouter } from"next/navigation";
exportdefaultfunctionLoginPage() {
return (
Кодът по-горе създава функционален компонент на страница за вход, който ще изобрази прост формуляр за вход в браузъра, за да позволи на потребителите да въвеждат потребителско име и парола.
The използвайте клиент в кода гарантира, че е декларирана граница между кода само за сървър и само за клиента в ап указател.
В този случай той се използва за деклариране, че кодът в страницата за вход, по-специално, на handleSubmitфункцията се изпълнява само на клиента; в противен случай Next.js ще изведе грешка.
Сега нека дефинираме кода за handleSubmit функция. Във функционалния компонент добавете следния код.
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");
}
};
За да управлява логиката за удостоверяване на вход, тази функция улавя потребителските идентификационни данни от формуляра за вход. След това изпраща POST заявка до крайна точка на API, като предава потребителските данни за проверка.
Ако идентификационните данни са валидни, което показва, че процесът на влизане е бил успешен — API връща статус на успех в отговора. След това функцията за обработка ще използва рутера на Next.js, за да навигира потребителя до определен URL адрес, в този случай защитени маршрут.
Дефинирайте крайната точка на API за влизане
Вътре в src/приложение директория, създайте нова папка и я наименувайте api. В тази папка добавете нова вход/route.js файл и включете кода по-долу.
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 });
}
Основната задача за този API е да провери идентификационните данни за вход, предадени в POST заявките, като използва фиктивни данни.
При успешна проверка, той генерира криптиран JWT токен, свързан с данните за удостоверения потребител. Накрая изпраща успешен отговор на клиента, включително токена в бисквитките за отговор; в противен случай връща отговор за състояние на грешка.
Внедрете логика за проверка на токена
Първоначалната стъпка в удостоверяването на токена е генерирането на токена след успешен процес на влизане. Следващата стъпка е внедряване на логиката за проверка на токена.
По същество ще използвате jwtVerify функция, предоставена от Хосе модул за проверка на JWT токените, предадени с последващи HTTP заявки.
В src директория, създайте нова libs/auth.js файл и включете кода по-долу.
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;
}
}
Тайният ключ се използва при подписване и проверка на токените. Чрез сравняване на подписа на декодирания токен с очаквания подпис, сървърът може ефективно да провери дали предоставеният токен е валиден и в крайна сметка да разреши заявките на потребителите.
Създавайте .env файл в основната директория и добавете уникален таен ключ, както следва:
NEXT_PUBLIC_JWT_SECRET_KEY=your_secret_key
Създайте защитен маршрут
Сега трябва да създадете маршрут, до който само удостоверени потребители могат да получат достъп. За да направите това, създайте нов protected/page.js файл в src/приложение указател. Вътре в този файл добавете следния код.
exportdefaultfunctionProtectedPage() {
return<h1>Very protected pageh1>;
}
Създайте кука за управление на състоянието на удостоверяване
Създайте нова папка в src директория и я наименувайте кукички. В тази папка добавете нова useAuth/index.js файл и включете кода по-долу.
"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;
}
Тази кука управлява състоянието на удостоверяване от страна на клиента. Той извлича и проверява валидността на JWT токена, присъстващ в бисквитките, използвайки verifyJwtToken функция и след това задава данните за удостоверения потребител на авт състояние.
По този начин той позволява на други компоненти да имат достъп и да използват информацията на удостоверения потребител. Това е от съществено значение за сценарии като извършване на актуализации на потребителския интерфейс въз основа на състоянието на удостоверяване, извършване на последващи API заявки или рендиране на различно съдържание въз основа на потребителски роли.
В този случай ще използвате куката, за да изобразите различно съдържание на У дома маршрут въз основа на състоянието на удостоверяване на потребителя.
Алтернативен подход, който може да обмислите, е манипулирането управление на състоянието с помощта на Redux Toolkit или наемане на a инструмент за управление на държавата като Jotai. Този подход гарантира, че компонентите могат да получат глобален достъп до състоянието на удостоверяване или всяко друго дефинирано състояние.
Продължете и отворете app/page.js файл, изтрийте шаблонния код Next.js и добавете следния код.
"use client" ;
import { useAuth } from"@/hooks/useAuth";
import Link from"next/link";
exportdefaultfunctionHome() {
const auth = useAuth();
return<>Public Home Page</h1>
Кодът по-горе използва useAuth кука за управление на състоянието на удостоверяване. По този начин той условно изобразява публична начална страница с връзка към Влизам маршрут на страницата, когато потребителят не е удостоверен, и показва параграф за удостоверен потребител.
Добавете мидълуер за налагане на оторизиран достъп до защитени маршрути
В src директория, създайте нова междинен софтуер.js файл и добавете кода по-долу.
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*"] };
Този код на междинния софтуер действа като пазач. Той проверява, за да гарантира, че когато потребителите искат достъп до защитени страници, те са удостоверени и упълномощени за достъп до маршрутите, в допълнение към пренасочването на неоторизирани потребители към страницата за вход.
Защита на Next.js приложения
Удостоверяването на токена е ефективен механизъм за сигурност. Това обаче не е единствената налична стратегия за защита на вашите приложения от неоторизиран достъп.
За да укрепите приложенията срещу динамичния пейзаж на киберсигурността, е важно да приемете всеобхватна сигурност подход, който цялостно адресира потенциални вратички в сигурността и уязвимости, за да гарантира задълбочено защита.