Получите больше контроля над логикой аутентификации вашего приложения 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, менеджер пакетов Node.

npm install jose universal-cookie

Хосе — это модуль JavaScript, который предоставляет набор утилит для работы с веб-токенами JSON, в то время как универсальное печенье зависимость обеспечивает простой способ работы с файлами cookie браузера как на стороне клиента, так и на стороне сервера.

Вы можете найти код этого проекта в этом Репозиторий GitHub.

Создайте пользовательский интерфейс формы входа

Открой источник/приложение каталог, создайте новую папку и назовите ее авторизоваться. Внутри этой папки добавьте новый страница.js файл и включите приведенный ниже код.

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

exportdefaultfunctionLoginPage() {
return (


Приведенный выше код создает функциональный компонент страницы входа в систему, который отображает в браузере простую форму входа, позволяющую пользователям вводить имя пользователя и пароль.

использовать клиент в коде гарантирует, что граница объявлена ​​между серверным и клиентским кодом в приложение каталог.

В данном случае он используется для объявления того, что код на странице входа, в частности, handleОтправитьфункция выполняется только на клиенте; в противном случае Next.js выдаст ошибку.

Теперь давайте определим код для handleОтправить функция. Внутри функционального компонента добавьте следующий код.

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 входа в систему

Внутри источник/приложение каталог, создайте новую папку и назовите ее 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, связанный с данными аутентифицированного пользователя. Наконец, он отправляет клиенту успешный ответ, включая токен в файлах cookie ответа; в противном случае он возвращает ответ о состоянии сбоя.

Реализация логики проверки токена

Первым шагом в аутентификации токена является создание токена после успешного процесса входа в систему. Следующим шагом является реализация логики проверки токена.

По сути, вы будете использовать jwtVerify функция, обеспечиваемая Хосе модуль для проверки токенов JWT, передаваемых с последующими HTTP-запросами.

в источник каталог, создайте новый библиотеки/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

Создайте защищенный маршрут

Теперь вам нужно создать маршрут, к которому смогут получить доступ только прошедшие проверку подлинности пользователи. Для этого создайте новый защищенный/page.js файл в источник/приложение каталог. Внутри этого файла добавьте следующий код.

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

Создайте перехватчик для управления состоянием аутентификации

Создайте новую папку в источник каталог и назовите его крючки. Внутри этой папки добавьте новый использоватьAuth/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, присутствующего в файлах cookie, с помощью проверитьJwtToken функцию, а затем устанавливает данные аутентифицированного пользователя в авторизация состояние.

Тем самым он позволяет другим компонентам получать доступ и использовать информацию аутентифицированного пользователя. Это важно для таких сценариев, как обновление пользовательского интерфейса на основе статуса аутентификации, выполнение последующих запросов API или отображение различного контента в зависимости от ролей пользователя.

В этом случае вы будете использовать хук для рендеринга различного контента в дом маршрут на основе состояния аутентификации пользователя.

Альтернативный подход, который вы можете рассмотреть, — это обработка управление состоянием с помощью Redux Toolkit или используя инструмент управления состоянием, такой как Jotai. Этот подход гарантирует, что компоненты могут получить глобальный доступ к состоянию аутентификации или любому другому определенному состоянию.

Идите вперед и откройте приложение/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>

В приведенном выше коде используется использоватьAuth крючок для управления состоянием аутентификации. При этом он условно отображает общедоступную домашнюю страницу со ссылкой на авторизоваться маршрут страницы, когда пользователь не аутентифицирован, и отображает абзац для аутентифицированного пользователя.

Добавьте промежуточное программное обеспечение для обеспечения авторизованного доступа к защищенным маршрутам

в источник каталог, создайте новый промежуточное программное обеспечение.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

Аутентификация по токену — эффективный механизм безопасности. Однако это не единственная доступная стратегия защиты ваших приложений от несанкционированного доступа.

Чтобы защитить приложения от динамичной среды кибербезопасности, важно принять комплексную систему безопасности. подход, который комплексно устраняет потенциальные лазейки и уязвимости безопасности, чтобы гарантировать тщательную защита.