- Вопрос или проблема
- Ответ или решение
- Интеграция Credential Provider и Google Provider в Next.js 14 с использованием NextAuth
- Шаг 1: Настройка окружения
- Шаг 2: Настройка базовых провайдеров
- Шаг 3: Конфигурация NextAuth API
- Шаг 4: Обработка вызовов колбэков
- Шаг 5: Управление пользовательским интерфейсом
- Заключение
Вопрос или проблема
Я пытаюсь конвертировать приложение mern в nextjs, но у меня возникли проблемы с next-auth. Я создаю пользователя с электронной почтой и паролем в отдельной форме регистрации, и если я перехожу к форме входа и на страницу AuthOptions, если я закомментирую колбэки внизу, вход с электронной почтой и паролем работает.
Провайдер Google работает без проблем, сохраняя пользователя в mongoDB, если его там нет.
Если я не закомментирую колбэки и попытаюсь войти, используя электронную почту и пароль, то выполняется часть профиля учетных данных, но затем пытается выполнить колбэки. Есть ли лучший способ? Я мучился, пытаясь заставить это работать, используя один учебник для настройки GoogleProvider и отдельный для настройки CredentialsProvider, но не могу заставить их работать вместе.
Вот мой /api/auth/[…nextauth]/route.js
import { authOptions } from "@/utils/authOptions";
import NextAuth from "next-auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
А вот мой файл authOptions:
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import connectDB from "@/lib/database";
import User from "@/models/User";
import bcrypt from "bcryptjs";
export const authOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: {
label: "email:",
type: "email",
name: "email",
placeholder: "your-email",
},
password: {
label: "password:",
type: "password",
name: "password",
placeholder: "your-password",
},
},
async authorize(credentials) {
try {
const foundUser = await User.findOne({
email: credentials.email,
}).lean();
if (foundUser) {
console.log("найден пользователь ", foundUser);
console.log("Пользователь существует");
const match = await bcrypt.compare(
credentials.password,
foundUser.password
);
if (match) {
console.log("Хороший пароль");
delete foundUser.password;
foundUser["role"] = "Неконтролируемая электронная почта";
return foundUser;
}
}
} catch (error) {
console.log(error);
}
return null;
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "согласие",
access_type: "offline",
response_type: "code",
},
},
}),
],
callbacks: {
async signIn({ profile }) {
await connectDB;
const userExists = await User.findOne({ email: profile.email });
if (!userExists) {
const username = profile.name.slice(" ");
await User.create({
firstName: username[0],
lastName: username[1],
email: profile.email,
image: profile.picture,
});
}
return true;
},
async session({ session }) {
const user = await User.findOne({ email: session.user.email });
session.user.id = user._id.toString();
return session;
},
},
};
Ответ или решение
Интеграция Credential Provider и Google Provider в Next.js 14 с использованием NextAuth
При переходе вашего MERN приложения на Next.js и использовании NextAuth для аутентификации, важно понимать, как одновременно интегрировать Credential Provider и Google Provider. Ниже приведено подробное руководство по настройке этих провайдеров в Next.js 14 и NextAuth.
Шаг 1: Настройка окружения
Убедитесь, что в вашем проекте установлены все необходимые зависимости:
npm install next-auth bcryptjs mongoose
Также, убедитесь, что у вас правильно настроены переменные окружения в файле .env.local
:
GOOGLE_CLIENT_ID=ваш_google_client_id
GOOGLE_CLIENT_SECRET=ваш_google_client_secret
MONGODB_URI=ваш_mongodb_uri
Шаг 2: Настройка базовых провайдеров
Убедитесь, что ваши провайдеры (GoogleProvider
и CredentialsProvider
) правильно настроены в файле authOptions
. Основная часть вашей настройки выглядит корректно, но давайте добавим несколько улучшений.
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import connectDB from "@/lib/database";
import User from "@/models/User";
import bcrypt from "bcryptjs";
export const authOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: { label: "Email", type: "email", placeholder: "your-email" },
password: { label: "Password", type: "password", placeholder: "your-password" },
},
async authorize(credentials) {
await connectDB(); // Убедитесь, что соединение с БД произошло
const { email, password } = credentials;
const foundUser = await User.findOne({ email }).lean();
if (foundUser && await bcrypt.compare(password, foundUser.password)) {
delete foundUser.password; // Удаляем пароль перед возвратом
return { ...foundUser, role: "Unverified Email" }; // Добавляем роль пользователя
}
return null; // Возвращаем null, если пользователь не найден
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
}),
],
callbacks: {
async signIn({ profile }) {
await connectDB(); // Обязательно вызывайте connectDB в каждом колбэке
const userExists = await User.findOne({ email: profile.email });
if (!userExists) {
const username = profile.name.split(" ");
await User.create({
firstName: username[0],
lastName: username[1],
email: profile.email,
image: profile.picture,
});
}
return true;
},
async session({ session }) {
const user = await User.findOne({ email: session.user.email });
session.user.id = user._id.toString();
return session;
},
},
};
Шаг 3: Конфигурация NextAuth API
Убедитесь, что ваш файл API корректно возвращает аутентификацию:
import { authOptions } from "@/utils/authOptions";
import NextAuth from "next-auth";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
Шаг 4: Обработка вызовов колбэков
Основная проблема, с которой вы столкнулись, заключается в конфликте между обработкой аутентификации через Credential Provider и вызовами колбэков. Убедитесь, что ваши колбэки обрабатываются корректно и не вызывают ошибок. Возможно, мы добавим обработку ошибок в колбэки, чтобы они не прерывали выполнение другого кода.
Шаг 5: Управление пользовательским интерфейсом
Когда вы работаете с формами входа и регистрации, убедитесь, что у вас есть правильная логика для обработки успешного и неудачного входа. Например, при неудачной попытке входа можно вернуть сообщение об ошибке, чтобы информировать пользователя.
Заключение
Теперь вы должны иметь работающее решение, которое интегрирует как Credential Provider, так и Google Provider для аутентификации пользователей в Next.js 14 с использованием NextAuth. Убедитесь, что вы протестировали оба метода аутентификации, чтобы гарантировать, что все работает корректно. В случае возникновения проблем, проверьте логи на наличие ошибок и убедитесь, что соединение с базой данных установлено корректно.
Если вы столкнетесь с дальнейшими проблемами, не стесняйтесь обращаться за помощью к сообществу разработчиков Next.js или просмотреть официальную документацию NextAuth для более глубокого понимания работы этих провайдеров.