Как получить сессию внутри функции getServerSideProps и в API-маршрутах в Next.js

Вопрос или проблема

import UserProfile из '../components/profile/user-profile';
// import { getSession } из 'next-auth/react';
import { getServerSession } из "next-auth/next"
import { authOptions } из './api/auth/[...nextauth]';
function ProfilePage() {
  return <UserProfile />;
}
export async function getServerSideProps(context){
  const session = await getServerSession(context.req, context.res, authOptions)
  console.log('здесь')
  console.log(session)
  if (!session) {
    return{
      redirect: {
        destination: '/auth',
        permanent: false
      }
    }
  }
  return{
    props: { session }
  }
}
export default ProfilePage;

//Параметры аутентификации

import NextAuth из "next-auth";
import CredentialsProvider из "next-auth/providers/credentials"; // Обновить импорт для провайдера учетных данных
import connectToDatabase из "../../../ib/db";
import { verifyPassword } из "../../../ib/auth";

export const authOptions = {
    session: {
        jwt: true, 
    },
    providers: [
        CredentialsProvider({
            name: 'Credentials',
            async authorize(credentials) {
                const client = await connectToDatabase(); 
                const userCollection = client.db().collection('users');

                const user = await userCollection.findOne({ email: credentials.email });
                if (!user) {
                    client.close();
                    throw new Error('Пользователь не найден!');
                }

                const isValid = await verifyPassword(credentials.password, user.password);
                if (!isValid) {
                    client.close();
                    throw new Error('Неверный пароль');
                }

                client.close();
                return { email: user.email }; 
            },
        }),
    ],
};
export default NextAuth(authOptions); 

//api маршрут

import { getServerSession } из "next-auth/next";
import connectToDatabase из "../../../ib/db";
import { hashPassword, verifyPassword } из "../../../ib/auth";
import { authOptions } из "../auth/[...nextauth]";
import { getSession } из "next-auth/react";
async function handler(req, res) {
  if (req.method !== "PATCH") {
    return res.status(405).json({ message: "Метод не разрешен" });
  }
  const session = await getServerSession(req, res, authOptions);
  if (!session) {
    return res.status(401).json({ message: "Запрос не авторизован" });
  }
  const userEmail = session.user.email;
  const { oldPassword, newPassword } = req.body;

  const client = await connectToDatabase();
  const usersCollection = client.db().collection('users');

  const user = await usersCollection.findOne({ email: userEmail });
  if (!user) {
    client.close();
    return res.status(404).json({ message: 'Пользователь не найден' });
  }

  const currentPassword = user.password;
  const passwordsAreEqual = await verifyPassword(oldPassword, currentPassword); // Добавлено `await`
  if (!passwordsAreEqual) {
    client.close();
    return res.status(403).json({ message: "Вы аутентифицированы, но не авторизованы" });
  }

  const hashedPassword = await hashPassword(newPassword); 
  const result = await usersCollection.updateOne(
    { email: userEmail },
    { $set: { password: hashedPassword } }
  ); 

  client.close();
  return res.status(200).json({ message: "Пароль обновлен" });
}

export default handler;

в приведенном выше коде мне нужно получить текущую сессию пользователя внутри серверного рендеринга. Для клиентской стороны функция getSeesion() работает нормально, но внутри api маршрутов и getServerProps функция getSession() не работает, и теперь я пытаюсь использовать getServerSession(), который очищает все куки, и я получаю null сессию, как мне решить эту проблему
Также я получаю следующее сообщение об ошибке

[next-auth][error][JWT_SESSION_ERROR] 
https://next-auth.js.org/errors#jwt_session_error ошибка расшифровки {
  message: 'ошибка расшифровки',
  stack: 'JWEDecryptionFailed: операция расшифровки не удалась\n' +
    '    at gcmDecrypt (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\runtime\\decrypt.js:67:15)\n' +  
    '    at decrypt (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\runtime\\decrypt.js:92:20)\n' +     
    '    at flattenedDecrypt (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\jwe\\flattened\\decrypt.js:143:52)\n' +
    '    at async compactDecrypt (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\jwe\\compact\\decrypt.js:18:23)\n' +
    '    at async jwtDecrypt (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\jwt\\decrypt.js:8:23)\n' + 
    '    at async Object.decode (D:\\personal\\authentication\\node_modules\\jose\\dist\\node\\cjs\\jwt\\index.js:66:7)\n' +
    '    at async Object.session (D:\\personal\\authentication\\node_modules\\next-auth\\node_modules\\next-auth\\core\\routes\\session.js:43:28)\n' +
    '    at async AuthHandler (D:\\personal\\authentication\\node_modules\\next-auth\\node_modules\\next-auth\\core\\index.js:165:27)\n' +
    '    at async getServerSession (D:\\personal\\authentication\\node_modules\\next-auth\\node_modules\\next-auth\\next\\index.js:159:19)\n' +      
    '    at async getServerSideProps (webpack-internal:///./pages/profile.js:25:21)',
  name: 'JWEDecryptionFailed'
}

Ответ или решение

Для того чтобы получить текущую сессию пользователя внутри функции getServerSideProps и внутри API маршрутов в Next.js, можно использовать функцию getServerSession из библиотеки next-auth.

1. Использование getServerSession в getServerSideProps

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

Пример вашего кода с getServerSession в getServerSideProps:

import UserProfile from '../components/profile/user-profile';
import { getServerSession } from "next-auth/next";
import { authOptions } from './api/auth/[...nextauth]';

function ProfilePage() {
  return <UserProfile />;
}

export async function getServerSideProps(context){
  const session = await getServerSession(context.req, context.res, authOptions);

  if (!session) {
    return {
      redirect: {
        destination: '/auth',
        permanent: false
      }
    }
  }

  return {
    props: { session }
  }
}

export default ProfilePage;

2. Использование getServerSession в API маршрутах

Аналогично, внутри API маршрутов вы также правильно используете getServerSession. Пример:

import { getServerSession } from "next-auth/next";
import connectToDatabase from "../../../ib/db";
import { hashPassword, verifyPassword } from "../../../ib/auth";
import { authOptions } from "../auth/[...nextauth]";

async function handler(req, res) {
  if (req.method !== "PATCH") {
    return res.status(405).json({ message: "Method not allowed" });
  }

  const session = await getServerSession(req, res, authOptions);

  if (!session) {
    return res.status(401).json({ message: "Unauthorized Request" });
  }

  const userEmail = session.user.email;
  const { oldPassword, newPassword } = req.body;

  const client = await connectToDatabase();
  const usersCollection = client.db().collection('users');

  const user = await usersCollection.findOne({ email: userEmail });
  if (!user) {
    client.close();
    return res.status(404).json({ message: 'User Not Found' });
  }

  const currentPassword = user.password;
  const passwordsAreEqual = await verifyPassword(oldPassword, currentPassword);
  if (!passwordsAreEqual) {
    client.close();
    return res.status(403).json({ message: "You are authenticated but not authorized" });
  }

  const hashedPassword = await hashPassword(newPassword); 
  await usersCollection.updateOne(
    { email: userEmail },
    { $set: { password: hashedPassword } }
  );

  client.close();
  return res.status(200).json({ message: "Password updated" });
}

export default handler;

Возможные ошибки и их устранение

Ошибка JWEDecryptionFailed, которую вы наблюдаете, может быть связана с неправильными настройками шифрования JWT. Обратите внимание на следующие возможные причины:

  1. Проверка ключа шифрования: Убедитесь, что вы правильно настроили NEXTAUTH_SECRET в переменных окружения. Это значение должно быть стабильным и уникальным.

    NEXTAUTH_SECRET=ваш_секретный_ключ
  2. Смена браузера или использование инкогнито: Иногда сессии могут повредиться, если вы меняете браузер или используете режим инкогнито. Попробуйте удалить куки и повторно войти в систему.

  3. Тестирование на локальном сервере: Убедитесь, что вы испытываете вашу аутентификацию в подходящей среде (на локальном сервере). Попробуйте запустить npm run dev и протестировать вашу реализацию.

Заключение

Если вы выполните все указанные шаги и проверите, что ваши конфигурации установлены правильно, вы сможете успешно использовать getServerSession в ваших API маршрутах и в функции getServerSideProps. Если проблемы продолжаются, можно рассмотреть возможность создания нового JWT-секрета и протестировать, остается ли проблема.

Оцените материал
Добавить комментарий

Капча загружается...