Поставщик Credentials и пользовательский вход
Аутентифицируйте пользователей через базу данных с помощью поставщика credentials и пользовательской формы входа.
«Поставщик Credentials и пользовательский вход» — бесплатный урок React Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.
Когда использовать провайдер Credentials
Используйте провайдер Credentials, если аутентификация выполняется через собственную базу данных (электронная почта и пароль), а не через провайдера OAuth. Это требует тщательной работы с хешированием паролей и безопасностью.
Определение провайдера Credentials
Добавьте Credentials в массив провайдеров. Функция authorize получает отправленные учётные данные и возвращает объект пользователя или null.
import Credentials from 'next-auth/providers/credentials';
import bcrypt from 'bcryptjs';
export const { handlers, auth } = NextAuth({
providers: [
Credentials({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials) {
const user = await db.user.findUnique({ where: { email: credentials.email as string } });
if (!user) return null;
const valid = await bcrypt.compare(credentials.password as string, user.passwordHash);
if (!valid) return null;
return { id: user.id, name: user.name, email: user.email };
},
}),
],
});Пользовательская форма входа
Создайте форму входа как клиентский компонент, который вызывает signIn('credentials', { email, password }) из next-auth/react.
'use client';
import { signIn } from 'next-auth/react';
export function LoginForm() {
const [error, setError] = useState('');
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const form = new FormData(e.currentTarget);
const result = await signIn('credentials', {
email: form.get('email'),
password: form.get('password'),
redirect: false, // handle redirect manually
});
if (result?.error) setError('Invalid email or password');
else router.push('/dashboard');
}
return (
<form onSubmit={handleSubmit}>
{error && <p className="error">{error}</p>}
<input name="email" type="email" required />
<input name="password" type="password" required />
<button type="submit">Sign in</button>
</form>
);
}redirect: false для обработки ошибок
Передайте redirect: false в signIn(), чтобы получить объект результата и обработать ошибки в компоненте, а не перенаправлять пользователя на страницу ошибки.
const result = await signIn('credentials', { email, password, redirect: false });
if (result?.error) {
// result.error is 'CredentialsSignin' for auth failures
setError('Invalid email or password');
}Валидация Zod в authorize
Проверяйте учётные данные с помощью Zod внутри функции authorize до обращения к базе данных.
import { z } from 'zod';
const schema = z.object({ email: z.string().email(), password: z.string().min(8) });
async authorize(credentials) {
const parsed = schema.safeParse(credentials);
if (!parsed.success) return null;
const { email, password } = parsed.data;
// ... db lookup
}Стратегия сессий для учётных данных
Провайдер учётных данных требует стратегии сессий JWT (для сессий адаптер базы данных не нужен). Явно задайте session: { strategy: 'jwt' }.
export const { handlers, auth } = NextAuth({
session: { strategy: 'jwt' },
providers: [Credentials({ ... })],
});Добавление пользовательских полей в сессию
Передавайте дополнительные данные пользователя через обратные вызовы JWT и сессии, чтобы сделать их доступными в useSession().
callbacks: {
async jwt({ token, user }) {
if (user) { token.id = user.id; token.role = user.role; }
return token;
},
async session({ session, token }) {
session.user.id = token.id as string;
session.user.role = token.role as string;
return session;
},
},Хеширование паролей
Всегда хешируйте пароли с помощью bcrypt перед сохранением. Никогда не храните пароли в открытом виде.
import bcrypt from 'bcryptjs';
// On registration:
const passwordHash = await bcrypt.hash(password, 12);
await db.user.create({ data: { email, passwordHash } });
// On login (in authorize):
const valid = await bcrypt.compare(submittedPassword, user.passwordHash);Ограничение частоты попыток входа
Защитите конечную точку учётных данных от перебора, ограничив частоту попыток входа с помощью промежуточного ПО или хранилища в памяти.
// middleware.ts or in a rate-limiting library
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(10, '10 s') });
// Check in authorize before DB query:
const { success } = await ratelimit.limit(credentials.email as string);
if (!success) return null;Процесс регистрации
Регистрация выполняется отдельно от Auth.js — создайте пользователя в базе данных (с хешированным паролем) через серверное действие или маршрут API, а затем выполните вход с помощью signIn('credentials', ...).
Быстрая проверка
Почему при вызове signIn() в пользовательской форме входа следует передавать redirect: false?
Итоги
Провайдер учётных данных вызывает вашу функцию authorize с отправленными данными формы. Выполните проверку с помощью Zod, сравните хешированные пароли с помощью bcrypt и верните объект пользователя или null. Для пользовательской обработки ошибок используйте redirect: false в форме и всегда применяйте стратегию JWT с учётными данными.
Часто задаваемые вопросы
Урок «Поставщик Credentials и пользовательский вход» бесплатный?
Да — полный текст урока «Поставщик Credentials и пользовательский вход» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.
Чему я научусь в уроке «Поставщик Credentials и пользовательский вход»?
Аутентифицируйте пользователей через базу данных с помощью поставщика credentials и пользовательской формы входа. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать React Academy?
Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Поставщик Credentials и пользовательский вход»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке React Academy?
Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Настройка Auth.js в App Router Next.js
- Управление сеансами и хук useSession
- Поставщик Credentials и пользовательский вход
- Защита маршрутов на основе промежуточного ПО