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

Вы можете использовать встроенную динамическую функцию cookies() для хранения этих данных в файлах cookie клиента, но проблема с использованием файлов cookie заключается в том, что они хранятся на стороне клиента и уязвимы для межсайтового скриптинга (XSS). , поэтому для конфиденциальных данных, таких как токены доступа, это не идеально.

Решение

Чтобы решить эту проблему, вы можете использовать сеансы на стороне сервера для безопасного хранения ваших данных. Вы можете использовать временный кеш памяти или службу структуры хранения данных, такую ​​​​как Redis, PostgreSQL, Dynamodb…. или другие.

С устаревшим маршрутизатором Page этого можно было добиться с помощью таких пакетов, как next-session, iron-session или express-session, но на момент написания этого руководства маршрутизатор приложений еще не поддерживался их.

Поэтому я написал пакет next-app-session, который работает с обработчиками маршрутов маршрутизатора приложений, серверными компонентами и серверными действиями. кроме того, он также поддерживает маршрутизатор страницы и промежуточное программное обеспечение.
https://www.npmjs.com/package/next-app-session

Как это работает

Прежде чем мы перейдем к тому, как использовать пакет, возможно, стоит описать, как он работает:

  1. Для новых пользователей/посетителей создается уникальный идентификатор сеанса пользователя. (ИДС)
  2. Этот SID будет храниться в файле cookie браузера клиента.
  3. При сохранении данных для пользователя его значение SID используется в качестве ключа для хранения этих данных в хранилище данных сервера, и эти данные будут связаны только с этим SID.
  4. Любой запрос на чтение данных сеанса сначала извлекает SID из пользовательских файлов cookie, а затем получает связанные данные из хранилища данных.

Выполнение

В этом руководстве мы будем использовать Redis в качестве хранилища данных. Если вы хотите использовать другие хранилища, этот пакет должен работать с любым пакетом экспресс-хранилища сеансов, если они передаются через promisifyStore служебную функцию.

Итак, давайте сначала настроим наш экземпляр хранилища Redis с помощью докера. Если у вас уже есть экземпляр Redis, вы можете пропустить эти шаги.

Настройка экземпляра магазина Redis

  1. Обновите/создайте файл docker-compose.yml, чтобы иметь службу Redis (убедитесь, что вы используете неиспользуемый локальный порт)
version: '3.8'
services:
 redis:
   image: redis:latest
   ports:
   - '6379:6379'

2. Запустите док-контейнер, в терминале перейдите к своему проекту и запустите: docker-compose up

Установить пакет сеанса следующего приложения

  1. Сначала вам нужно установить пакет вместе с пакетами Redis.
    npm i next-app-session ioredis connect-redis
  2. Создайте файл инициализации, для этого примера мы создадим этот файл lib/session.ts и добавим следующий код:
import nextAppSession, {promisifyStore} from 'next-app-session';
import Redis from 'ioredis';
import RedisStoreFactory from 'connect-redis';

// Your session data type
type MySessionData = {
  access_token?: string;
  refresh_token?: string;
  counter?: number;
}

export const session = nextAppSession<MySessionData>({
  name: 'EXAMPLE_SID', // The cookie name that will hold sid
  secret: 'secret goes here' , // Providing a secret will sign the SID before storing it in the cookie, providing extra security
  // Assign Redis store with connection details
  store: promisifyStore(
    new RedisStore({
      client: new Redis({
        // The redis instance connection details
        host: 'localhost',
        port: 6379
      }),
      prefix: 'exampleapp:' // having a prefix is optional but can be usefull if redis service is used by multiple applications
    })
  )
}); 

Использование

Теперь, когда у вас настроены пакеты, вы можете начать использовать функцию session().

Важно: теперь вы можете использовать session() только для Чтения данных сеанса в Компонентах сервера или Чтения и записи данных в Обработчиках маршрутов и Действия сервера. Она следует тем же правилам использования, что и динамическая функция cookie().

Пример обработчика маршрута:

// Example for route handler
import { session } from '../lib/session'; //We import it from the initialisation file we created earlier

// Increment counter
export async function POST(request: Request) {
  // Read counter value froms session
  const current = await session().get('counter');

  //Increment value or assign 1 if no value exists
  const newValue = current ? Number(current) + 1 : 1;

  // Update counter session
  await session().set('counter', newValue);
}

Подробнее о настройке и использовании пакета можно узнать в README.file проекта