0Pricing
React Academy · Урок

Поставщик 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 — локальная установка не требуется.

Все уроки этого курса

  1. Настройка Auth.js в App Router Next.js
  2. Управление сеансами и хук useSession
  3. Поставщик Credentials и пользовательский вход
  4. Защита маршрутов на основе промежуточного ПО
← Назад к React Academy