Аутентификация (Frontend)
В этом разделе описаны механизмы аутентификации пользователей на стороне frontend, включая различные способы входа, регистрации и управления сессиями пользователей.
Обзор аутентификации
Boilerplate использует NextAuth.js для управления аутентификацией на стороне frontend. NextAuth.js предоставляет удобный API для работы с различными провайдерами аутентификации, такими как OAuth (Google, GitHub и т.д.), учетные данные (email/пароль) и Magic Links.
Настройка NextAuth.js
Настройка NextAuth.js находится в файле app/api/auth/[...nextauth]/route.ts
. Этот файл определяет конфигурацию аутентификации, включая провайдеров, коллбэки и другие параметры.
import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
Основные настройки аутентификации находятся в файле lib/auth.ts
:
import { PrismaAdapter } from "@auth/prisma-adapter";
import { NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import { db } from "@/lib/db";
import { verify } from "@/lib/password";
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(db),
session: {
strategy: "jwt",
},
pages: {
signIn: "/login",
},
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
}),
CredentialsProvider({
name: "Учетные данные",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Пароль", type: "password" },
},
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
return null;
}
const user = await db.user.findUnique({
where: { email: credentials.email },
});
if (!user) {
return null;
}
const isPasswordValid = await verify(
user.password,
credentials.password
);
if (!isPasswordValid) {
return null;
}
return {
id: user.id,
email: user.email,
name: user.name,
};
},
}),
],
callbacks: {
// Дополнительные коллбэки...
},
};
Компоненты аутентификации
Форма входа
Компонент формы входа в систему:
"use client";
import { useState } from "react";
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export function LoginForm() {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
setError("");
try {
const result = await signIn("credentials", {
email,
password,
redirect: false,
});
if (result?.error) {
setError("Неверный email или пароль");
setIsLoading(false);
return;
}
router.push("/dashboard");
} catch (error) {
setError("Произошла ошибка при входе. Попробуйте снова.");
setIsLoading(false);
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Пароль</Label>
<Input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <p className="text-red-500 text-sm">{error}</p>}
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "Вход..." : "Войти"}
</Button>
</form>
);
}
Кнопка для входа через Google
"use client";
import { signIn } from "next-auth/react";
import { Button } from "@/components/ui/button";
import { FcGoogle } from "react-icons/fc";
export function GoogleLoginButton() {
return (
<Button
variant="outline"
className="w-full"
onClick={() => signIn("google", { callbackUrl: "/dashboard" })}
>
<FcGoogle className="mr-2 h-5 w-5" />
Войти через Google
</Button>
);
}
Защита маршрутов
Для защиты приватных маршрутов от неавторизованных пользователей можно использовать middleware:
// middleware.ts
import { withAuth } from "next-auth/middleware";
import { NextResponse } from "next/server";
export default withAuth(
function middleware(req) {
// Дополнительная логика авторизации
return NextResponse.next();
},
{
callbacks: {
authorized({ token }) {
return !!token;
},
},
}
);
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*", "/protected/:path*"],
};
Получение данных текущего пользователя
Для доступа к данным текущего пользователя в клиентских компонентах можно использовать хук useSession:
"use client";
import { useSession } from "next-auth/react";
export function ProfileInfo() {
const { data: session, status } = useSession();
if (status === "loading") {
return <div>Загрузка...</div>;
}
if (status === "unauthenticated") {
return <div>Пожалуйста, войдите в свой аккаунт</div>;
}
return (
<div>
<h2>Профиль</h2>
<p>Имя: {session?.user?.name}</p>
<p>Email: {session?.user?.email}</p>
</div>
);
}
В серверных компонентах можно использовать функцию getServerSession:
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/lib/auth";
export default async function DashboardPage() {
const session = await getServerSession(authOptions);
if (!session) {
// Перенаправление или отображение сообщения
return <div>Пожалуйста, войдите в свой аккаунт.</div>;
}
return (
<div>
<h1>Добро пожаловать, {session.user.name}!</h1>
{/* Содержимое панели управления */}
</div>
);
}
Выход из системы
Компонент для выхода из системы:
"use client";
import { signOut } from "next-auth/react";
import { Button } from "@/components/ui/button";
export function LogoutButton() {
return (
<Button
variant="ghost"
onClick={() => signOut({ callbackUrl: "/" })}
>
Выйти
</Button>
);
}
Дополнительные возможности
- Настройка страниц ошибок аутентификации
- Интеграция Magic Links для входа без пароля
- Добавление двухфакторной аутентификации (2FA)
- Настройка сессий и токенов JWT
- Интеграция с другими OAuth провайдерами (GitHub, Facebook, Twitter)