В первый раз, когда я работал с OAuth 2.0, это был проект, требующий аутентификации в Google, я думал, что это будет просто, так как это технология, которая массово применяется в современных приложениях, но это была головная боль, потому что я не не понимаю, как сохранить данные от Google, должен ли я вернуть токен доступа, который исходит от провайдера, или я должен подписать JWT на всю жизнь. Поэтому я хочу объяснить это вам подробно. Самый простой из возможных способов.

Стратегию, которой я следовал, я не считаю лучшей, на самом деле не существует «лучшей стратегии», но она очень хорошо сработала для меня.

Последовательность действий следующая:

  1. Пользователь перенаправляется на конечную точку на нашем сервере и автоматически перенаправляется на экран входа в Google.
  2. После размещения ваших учетных данных вы будете перенаправлены на другую конечную точку нашего сервера, где мы будем получать всю информацию о пользователе.
  3. Мы будем искать пользователя в нашей базе данных
    Если пользователь существует: мы возвращаем файл cookie с веб-токеном JSON, который содержит идентификатор пользователя и адрес электронной почты
    Если пользователь пользователь не существует: мы регистрируем пользователя в нашей базе данных и возвращаем файл cookie
  4. Мы используем веб-токен JSON для выполнения аутентифицированных запросов.

Прежде чем начать, мы должны установить следующие пакеты с помощью NPM или Yarn в зависимости от вашего случая.

npm install @nestjs/jwt @nestjs/passport паспорт паспорт-google-oauth2 паспорт-jwt паспорт-локальный

npm install -D @types/passport-google-oauth2 @types/passport-jwt @types/passport-jwt @types/passport-local

Сначала создаем проект в консоли разработчика Google, во всех провайдерах он одинаков. Перейдите на https://console.cloud.google.com/projectcreate

Перейдем к API, затем на вкладку Учетные данные, Настроить экран согласия.

Заполняем всю форму данными нашего приложения

Возвращаемся в Credentials › Create Credentials › OAuth Client ID. Выберите веб-приложение и введите имя

Затем в JavaScript авторизированных доменах ставим домен нашего сервера, в режиме разработки это будет localhost

В доменах перенаправления мы помещаем домен, на который пользователь будет перенаправлен при входе в систему, у нас обычно будет что-то вроде http://localhost:8080/api/auth/google/callback, то же самое с каждым поставщиком аутентификации, который мы включаем в нашем приложении

Нажимаем «Создать» и все! У нас уже есть часть поставщика, теперь нам нужно только настроить все на нашем сервере.

Мы создаем папку с именем auth, где мы будем хранить всю логику аутентификации нашего приложения, внутри у нас будет несколько вещей, 2 Authentication Guardians, один для аутентификации в Google, а другой для запросов, требующих JWT.

У нас будет 2 стратегии Passport, стратегия для каждого поставщика аутентификации, в данном случае у нас есть только Google, и еще одна стратегия для извлечения JWT из файлов cookie, таким образом мы будем проверять личность пользователя в каждом запросе, чтобы дать или нет доступа к ресурсам, наконец, базовый контроллер и сервис любого модуля Nest.

Опекун Google, мы упрощаем, мы создаем класс GoogleOAuthGuard, который расширяется от класса AuthGuard @nest/passport с идентификатором google

В папке Strategies создадим файл google.strategy.ts, в нем почти все и происходит.

Мы создаем класс GoogleStrategy, который расширяет PassportStrategy, этот класс получает 2 параметра, стратегию и идентификатор стратегии, мы импортируем стратегию из пакета passport-google-oauth2 и в имени стратегии мы поместите 'google'

В конструкторе мы передаем супер со следующими параметрами:
clientID: наш идентификатор клиента, предоставленный Google
clientSecret: наш секрет клиента, предоставленный google
callbackURL: наш URL-адрес перенаправления, который мы ранее настроили в консоли Google
scopes: массив с информацией, которую мы хотим получить от пользователя , чаще всего это профиль и электронная почта

В моем случае я поместил всю информацию в переменные среды из соображений безопасности, вы должны сделать то же самое.

Затем мы создаем функцию validate(), которая принимает 4 обязательных параметра.
accessToken
refreshToken,
профиль и функция done,
Токен доступа нам пригодится для взаимодействия с сервисами Google, но в нашем случае это не обязательно, мы будет использовать только профиль, объект со всей информацией о пользователе, и готово, функция обратного вызова, в которую мы передадим объект пользователя и используем позже, чтобы зарегистрировать его в базе данных и подписать JWT.

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

В контроллере мы создадим метод GET с конечной точкой «google», которая использует ранее созданный google guard, эта конечная точка перенаправит пользователя на страницу входа в Google.

В службе у нас будет несколько методов.
В конструкторе мы создаем экземпляр службы JWT для создания токенов и службы пользователя для регистрации пользователя.
Метод generateJwt получает полезную нагрузку и возвращает подписанный JWT, полезной нагрузкой может быть идентификатор пользователя, электронная почта или что угодно.

Метод signIn получает объект пользователя, сначала ищет пользователя по электронной почте, если не находит, значит пользователь не зарегистрирован в нашей базе данных, мы должны зарегистрировать его в соответствии с моделью пользователя, которую мы определили, мы регистрируем пользователя в нашей базе данных и возвращаем JWT с идентификатором пользователя и адресом электронной почты.
Если пользователь существует, мы просто возвращаем JWT.

Мы создаем еще одну конечную точку в контроллере, на этот раз указывающую на ранее настроенную конечную точку перенаправления.

Этот метод будет содержать пользовательский объект в запросе, мы обращаемся к нему с помощью req.user, мы вызываем метод signIn, созданный в службе, и мы передаем пользователя, этот метод возвращает JWT, подписанный с информацией о пользователе, мы возвращаем файл cookie с токеном и кодом успеха.

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

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

Мы создаем New Guard с именем jwt.

Затем мы создаем Новую стратегию с именем jwt, в super мы передаем следующие параметры:
ignoreExpiration: false
secretOrKey: наш секретный ключ JWT, это может быть хэш или что угодно, но он должен быть секретным.
jwtFromRequest: функция, которая получает объект запроса в качестве параметра и проверяет, файл cookie access_token существует, если он есть, он возвращает его, а если нет, то извлекает токен из заголовков с помощью функцииpassport-jwt.

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

🥳 У нас уже есть готовая аутентификация в Google. Если вы хотите добавить больше поставщиков, вы должны выполнить те же действия и создать стратегию для каждого поставщика.

Если пост был для вас полезен, поставьте лайк👏 и подпишитесь на меня, вы мне очень поможете. Спасибо ❤️