Перевод статьи «Django REST Framework Authentication with Auth.js».
В этом уроке рассматривается реализация системы аутентификации на основе Django REST (с помощью Django REST Framework) и ее интеграция с Auth.js (ранее известным как NextAuth.js) во фронтенде. Мы разберем настройку аутентификации на основе учетных данных, а также аутентификацию с помощью Google.
Стандартная система аутентификации Django является отличным готовым решением для полнофункциональных Django-проектов. Тем не менее, при использовании Django REST Framework с клиент-серверной архитектурой использовать встроенную аутентификацию Django может быть довольно сложно. Кроме того, Django не поддерживает social auth.
К счастью, вы можете расширить систему аутентификации Django и добавить поддержку social auth с помощью пакетов django-allauth и dj-rest-auth, разработанных сообществом. После того как система аутентификации будет настроена, подключиться к ней из фронтенда будет довольно просто.
Хотя аутентификацию на основе учетных данных во фронтенде реализовать легко, проблемы возникают при добавлении social auth. Все социальные провайдеры разные, и добавление поддержки каждого из них по отдельности может занять очень много времени.
В связи с этим появилась библиотека Auth.js. Это стандартизированное решение аутентификации с открытым исходным кодом для Next.js, SvelteKit и SolidStart. В библиотеке реализованы аутентификация на основе учетных данных, аутентификация без пароля, социальная аутентификация и многое другое. Она также поддерживает более 60 социальных провайдеров.
В этом руководстве мы рассмотрим, как реализовать систему аутентификации на основе REST-технологии Django и подключиться к ней с помощью фронтенда Next.js. К концу этого урока у вас будет полностью рабочая система аутентификации, поддерживающая социальную аутентификацию. Сначала мы поработаем над бэкендом, а затем перейдем к фронтенду.
Реализованное решение будет иметь следующий поток аутентификации:
К концу этого урока вы сможете:
В этом разделе мы создадим новый проект Django, запустим специальное приложение для аутентификации, установим и настроим все зависимости, а также протестируем систему аутентификации через cURL.
Вы можете пропустить настройку Django и продолжить работу с вашим проектом.
Начните с создания нового каталога для вашего проекта и виртуальной среды:
$ mkdir django-rest-authjs && cd django-rest-authjs $ python3.11 -m venv env $ source env/bin/activate (env)$
Затем установите Django и загрузите новый проект:
(env)$ pip install Django==4.2.3 (env)$ django-admin startproject core .
Примените миграции и запустите сервер:
(env)$ python manage.py migrate (env)$ python manage.py runserver
Наконец, откройте ваш любимый браузер и перейдите по адресу http://localhost:8000. Вы должны увидеть стандартную главную страницу Django.
Чтобы сделать наш проект более организованным, мы создадим специальное приложение для аутентификации. Приложение будет включать в себя представления аутентификации и URL-адреса.
Создайте новое приложение:
(env)$ python manage.py startapp authentication
Добавьте его в INSTALLED_APPS
в core/settings.py:
# core/settings.py INSTALLED_APPS = [ # ... "authentication.apps.AuthenticationConfig", ]
Создайте на уровне приложения файл urls.py в папке authentication:
# authentication/urls.py from django.urls import path from . import views urlpatterns = [ # URLs will come here ]
Зарегистрируйте новый urls.py глобально:
# core/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('api/auth/', include('authentication.urls')), path("admin/", admin.site.urls), ]
На этом первоначальная настройка закончена.
В этом разделе мы настроим Django REST Framework, django-allauth и dj-rest-auth для включения аутентификации на основе учетных данных. Кроме того, мы настроим django-cors-headers, чтобы избежать проблем с CORS при подключении из фронтенда.
Начните с установки Django REST Framework:
(env)$ pip install djangorestframework==3.14.0
Далее перейдите к core/settings.py и добавьте его в INSTALLED_APPS
с authtoken
:
# core/settings.py INSTALLED_APPS = [ # ... "rest_framework", "rest_framework.authtoken", ]
Приложение authtoken
необходимо, поскольку мы будем использовать аутентификацию на основе токенов вместо стандартной аутентификации Django SessionAuthentication. Токен-аутентификация больше подходит для клиент-серверных систем.
Существует две системы аутентификации на основе токенов, из которых мы можем выбрать:
Я рекомендую использовать JWT-аутентификацию с помощью плагина djangorestframework-simplejwt. JWT-аутентификация лучше тем, что она более безопасна, проще для базы данных и имеет стандартизированные HTTP-ответы.
Чтобы установить плагин Simple JWT, выполните команду:
$(env) pip install djangorestframework-simplejwt==5.2.2
Далее добавьте его в INSTALLED_APPS
под rest_framework.authtoken
:
# core/settings.py INSTALLED_APPS = [ # ... "rest_framework.authtoken", "rest_framework_simplejwt", ]
Затем добавьте следующие настройки в нижнюю часть файла core/settings.py:
# core/settings.py SIMPLE_JWT = { "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60), "REFRESH_TOKEN_LIFETIME": timedelta(days=7), "ROTATE_REFRESH_TOKENS": False, "BLACKLIST_AFTER_ROTATION": False, "UPDATE_LAST_LOGIN": True, "SIGNING_KEY": "complexsigningkey", # generate a key and replace me "ALGORITHM": "HS512", }
Не стесняйтесь изменять эти параметры в соответствии со своими потребностями. Чтобы узнать, что делает каждая переменная, ознакомьтесь с официальной документацией.
Не забывайте об импорте:
from datetime import timedelta
Наконец, измените класс аутентификации DRF по умолчанию:
# core/settings.py REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework_simplejwt.authentication.JWTAuthentication", ] }
Сначала установите django-allauth:
(env)$ pip install django-allauth==0.52.0
Далее перейдите к файлу settings.py и добавьте приложение в INSTALLED_APPS
вместе с приложениями account
и socialaccount
:
# core/settings.py INSTALLED_APPS = [ "django.contrib.sites", # Убедитесь, что 'django.contrib.sites' установлен # ... "allauth", "allauth.account", "allauth.socialaccount", # Добавьте, если хотите социальную аутентификацию ]
django-allauth зависит от фреймворка Django «sites», поэтому убедитесь, что он у вас установлен. Кроме того, убедитесь, что у вас установлен SITE_ID
:
# core/settings.py SITE_ID = 1 # make sure SITE_ID is set
Далее необходимо отключить функцию проверки электронной почты:
# core/settings.py ACCOUNT_EMAIL_REQUIRED = False ACCOUNT_EMAIL_VERIFICATION = "none"
Проверка электронной почты должна быть отключена на этом шаге, поскольку наш проект Django не настроен на рассылку писем. Кроме того, у нас нет эндпоинтов, которые позволяли бы пользователям проверять свои адреса электронной почты.
Наконец, еще раз выполните миграцию базы данных:
(env)$ python manage.py migrate
Давайте установим dj-rest-auth:
(env)$ pip install "dj-rest-auth[with_social]==4.0.0"
Нам необходимо использовать спецификатор with_social
, так как мы хотим включить стандартный процесс регистрации. Кроме того, мы будем использовать этот пакет позже, когда включим социальную аутентификацию.
Далее перейдите к core/settings.py и добавьте приложение в INSTALLED_APPS
:
# core/settings.py INSTALLED_APPS = [ # ... "dj_rest_auth", "dj_rest_auth.registration", ]
Затем добавьте в settings.py следующие параметры конфигурации:
# core/settings.py REST_AUTH = { "USE_JWT": True, "JWT_AUTH_HTTPONLY": False, }
Примечания:
USE_JWT
требуется, поскольку мы используем djangorestframework-simplejwt.JWT_AUTH_HTTPONLY
должен быть выключен, иначе dj-rest-auth не будет отправлять токены обновления.Все настройки REST_AUTH смотрите в официальной документации.
На момент написания статьи в официальном руководстве по установке указано, что необходимо зарегистрировать dj_rest_auth.urls
. Я не рекомендую этого делать, поскольку URL по умолчанию содержат неработающие URL при неправильной настройке (например, сброс пароля, проверка электронной почты).
Вместо этого загляните в исходный код dj-rest-auth и вручную подберите необходимые URL-адреса:
# authentication/urls.py from dj_rest_auth.jwt_auth import get_refresh_view from dj_rest_auth.registration.views import RegisterView from dj_rest_auth.views import LoginView, LogoutView, UserDetailsView from django.urls import path from rest_framework_simplejwt.views import TokenVerifyView urlpatterns = [ path("register/", RegisterView.as_view(), name="rest_register"), path("login/", LoginView.as_view(), name="rest_login"), path("logout/", LogoutView.as_view(), name="rest_logout"), path("user/", UserDetailsView.as_view(), name="rest_user_details"), path("token/verify/", TokenVerifyView.as_view(), name="token_verify"), path("token/refresh/", get_refresh_view().as_view(), name="token_refresh"), ]
Последний пакет, который нам необходимо установить и настроить, — это django-cors-headers. Этот пакет будет устанавливать правильные CORS-заголовки при взаимодействии нашего фронтенда с бэкендом.
Установка:
$(env) pip install django-cors-headers==4.1.0
Добавьте его в INSTALLED_APPS
в core/settings.py:
# core/settings.py INSTALLED_APPS = [ # ... "corsheaders", ]
Добавьте CorsMiddleware
в список MIDDLEWARE
:
# core/settings.py MIDDLEWARE = [ # ... "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", # ... ]
CorsMiddleware
следует размещать как можно выше. Особенно перед любым промежуточным ПО, которое может генерировать ответы, таким как CommonMiddleware
или WhiteNoiseMiddleware
.
Наконец, добавьте следующие настройки в нижнюю часть core/settings.py:
# core/settings.py if DEBUG: CORS_ALLOW_ALL_ORIGINS = True else: CORS_ALLOWED_ORIGINS = [ "http://localhost:3000/", "http://127.0.0.1:3000/", ]
Отлично! Вот и все.
Теперь у вас есть полностью рабочая система аутентификации на основе учетных данных, использующая веб-токены JSON.
Для тестирования API мы будем использовать cURL. Ответы мы также будем передавать в jq для их автоматического форматирования и выделения цветом.
Начните с запуска сервера разработки Django:
(env)$ python manage.py runserver
Во-первых, создайте пользователя:
$ curl -XPOST -H "Content-type: application/json" -d '{ "username": "user1", "password1": "complexpassword123", "password2": "complexpassword123" }' 'http://localhost:8000/api/auth/register/' | jq
Вы должны получить аналогичный ответ:
{ "access": "eyJhb...", "refresh": "eyJhb...", "user": { "pk": 1, "username": "user1", "email": "" } }
Теперь для аутентификации можно использовать токен access
. Он действителен в течение времени, указанного в core/settings.py, после чего его необходимо обновить с помощью токена refresh
.
Войдите в систему под именем вновь созданного пользователя:
$ curl -XPOST -H "Content-type: application/json" -d '{ "username": "user1", "password": "complexpassword123" }' 'http://localhost:8000/api/auth/login/' | jq
Ответ будет аналогичен этому:
{ "access": "eyJhb...", "refresh": "eyJhb...", "user": { "pk": 1, "username": "user1", "email": "" } }
Получение данных о пользователе по полученному токену access
:
$ curl -XGET -H 'Authorization: Bearer <your_access_token>' \ -H "Content-type: application/json" 'http://localhost:8000/api/auth/user/' | jq
Ответ:
{ "pk": 1, "username": "user1", "email": "" }
Чтобы убедиться в том, что токен все еще действителен, можно передать его в /api/auth/token/verify/ следующим образом:
$ curl -XPOST -H "Content-type: application/json" -d '{ "token": "<your_access_token>" }' 'http://localhost:8000/api/auth/token/verify/' | jq
Ответ:
{}
Коды состояния:
200
означает, что токен все еще действителен4xx
означает, что токен больше не действителенЧтобы получить обновленный токен access
, необходимо использовать свой токен refresh
следующим образом:
$ curl -XPOST -H "Content-type: application/json" -d '{ "refresh": "your_refresh_token>" }' 'http://localhost:8000/api/auth/token/refresh/' | jq
Ответ:
{ "access": "eyJhb...", "access_expiration": "2023-07-11T17:42:22.480739Z" }
Ответ будет содержать новый токен access
и время его действия.
Для выхода пользователя из системы попробуйте отправить следующий запрос:
$ curl -XPOST -H 'Authorization: Bearer <your_access-token>' \ -H "Content-type: application/json" 'http://localhost:8000/api/auth/logout/' | jq
Ответ:
{ "detail": "Neither cookies or blacklist are enabled. Delete the token on client." }
Поскольку мы отключили cookies и не настроили черный список, этот эндпоинт ничего не делает. Нет необходимости вызывать его при выходе пользователя из системы. Единственное, что нужно сделать, это удалить токен из клиента.
Если вам нужен более надежный подход, настройте черный список с помощью приложения JWT Blacklist.
В этом разделе мы рассмотрим, как настроить социальную аутентификацию. Я расскажу, как настроить социальную аутентификацию в Google, но вы можете использовать аналогичные шаги для любого другого социального провайдера.
Если вы не заинтересованы в настройке социальной аутентификации, можете пропустить этот раздел.
Чтобы включить функцию Google sign up, сначала необходимо создать ключ OAuth Client. Перейдите в Google Cloud Console, выберите проект, который вы хотите использовать, и выполните поиск «API Credentials»:
Далее нажмите на кнопку «Create credentials» и выберите в выпадающем списке «OAuth Client ID»:
Выберите «Web-приложение», задайте пользовательское имя и добавьте URL-адрес вашего фронтенда в качестве URI авторизованного перенаправления. Для удобства тестирования я рекомендую также добавить:
Наконец, нажмите кнопку «Создать», чтобы сгенерировать учетные данные:
Вам будут представлены «Идентификатор клиента» и «Секрет клиента». Запишите их, так как они понадобятся нам на следующем этапе.
Двигаясь дальше, вернитесь в свой проект Django и добавьте следующее приложение в INSTALLED_APPS
:
# core/settings.py INSTALLED_APPS = [ # ... "allauth.socialaccount.providers.google", ]
Далее добавьте настройку SOCIALACCOUNT_PROVIDERS
в core/settings.py следующим образом:
# core/settings.py SOCIALACCOUNT_PROVIDERS = { "google": { "APP": { "client_id": "<your google client id>", # replace me "secret": "<your google secret>", # replace me "key": "", # leave empty }, "SCOPE": [ "profile", "email", ], "AUTH_PARAMS": { "access_type": "online", }, "VERIFIED_EMAIL": True, }, }
Обязательно замените <your google client id>
и <your google secret>
на ваши реальные ключи. Оставьте свойство key
пустым, поскольку оно не требуется для социальной аутентификации Google.
Добавьте в authentication/views.py новое представление, которое наследует от SocialLoginView
:
# authentication/views.py from dj_rest_auth.registration.views import SocialLoginView from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter from allauth.socialaccount.providers.oauth2.client import OAuth2Client class GoogleLogin(SocialLoginView): adapter_class = GoogleOAuth2Adapter callback_url = "http://127.0.0.1:3000/" client_class = OAuth2Client
Наконец, добавьте в authentication/urls.py следующие два URL:
# authentication/urls.py from allauth.socialaccount.views import signup from authentication.views import GoogleLogin urlpatterns = [ # ... path("google/", GoogleLogin.as_view(), name="google_login"), ]
Не забывайте об импорте:
from authentication.views import GoogleLogin
Для проверки работоспособности эндпоинта API необходимо сначала получить id_token
и затем отправить его на эндпоинт бэкенда. Проще всего получить id_token
через Google’s OAuth 2.0 Playground.
Далее передайте id_token
в качестве access_token
в теле запроса cURL:
$ curl -XPOST -H "Content-type: application/json" -d '{ "access_token": "<your_id_token>" }' 'http://localhost:8000/api/auth/google/'
Вы должны получить аналогичный ответ:
{ "access": "eyJhb...", "refresh": "eyJhb...", "user": { "pk": 2, "username": "user2", "email": "" } }
Теперь для аутентификации можно использовать токен access
.
В этом разделе мы напишем проект на Next.js, настроим Chakra UI, установим и настроим Auth.js, включим аутентификацию на основе учетных данных и социальную аутентификацию. Наконец, мы протестируем систему аутентификации.
Веб-приложение будет иметь следующие эндпоинты:
/
предлагает пользователю войти в систему/profile
отображает информацию об учетной записи пользователя/api/auth/...
обрабатывается динамическим API-маршрутизатором Auth.jsПервые два пункта можно пропустить и продолжить работу с собственным проектом.
Начните с вызова create-next-app
для генерации проекта Next.js:
$ npx create-next-app@13.4.9 django-rest-authjs-frontend √ Would you like to use TypeScript? ... Yes √ Would you like to use ESLint? ... Yes √ Would you like to use Tailwind CSS? ... No √ Would you like to use `src/` directory? ... No √ Would you like to use App Router? (recommended) ... No √ Would you like to customize the default import alias? ... No Creating a new Next.js app in ~\django-rest-authjs-frontend.
Для простоты я рекомендую ответить «Да» только на TypeScript и ESLint.
Для упрощения процесса создания пользовательского интерфейса мы будем использовать Chakra UI — минималистичную, модульную и доступную библиотеку компонентов для быстрого создания пользовательских интерфейсов React. В библиотеке есть встроенные компоненты, специализированные хуки, система стилей и многое другое.
Не стесняйтесь заменять Chakra UI на MUI, AntDesign, TailwindCSS или любую другую библиотеку фронтенда.
Установите библиотеку, выполнив следующую команду:
$ npm i @chakra-ui/react@2.5.5 @chakra-ui/next-js@2.1.4 @emotion/react@11.10.6 \ @emotion/styled@11.10.6 framer-motion@10.12.4
Далее создайте новую тему с помощью extendTheme()
и оберните Component
с ChakraProvider
в pages/_app.tsx примерно так:
// pages/_app.tsx import type {AppProps} from "next/app"; import {ChakraProvider, extendTheme} from "@chakra-ui/react"; export const theme = extendTheme({}); export default function App({Component, pageProps: {session, ...pageProps}}: AppProps) { return ( <ChakraProvider theme={theme}> <Component {...pageProps} /> </ChakraProvider> ); }
Не забывайте об импорте:
import {ChakraProvider, extendTheme} from "@chakra-ui/react";
Мы создали новую тему, поскольку в следующем шаге нам нужно будет передать ее скрипту цветового режима. Кроме того, определение темы таким образом позволяет в будущем легко настроить Chakra.
Далее займемся сценарием цветового режима.
Скрипт цветового режима обеспечивает корректную работу синхронизации локального хранилища. Он должен быть добавлен перед любым содержимым (в нашем случае в файл pages/_document.tsx).
Включите ColorModeScript
в свой pages/_document.tsx примерно так:
// pages/_document.tsx import {Head, Html, Main, NextScript} from "next/document"; import {ColorModeScript} from "@chakra-ui/react"; import {theme} from "./_app"; export default function Document() { return ( <Html lang="en"> <Head/> <body> <ColorModeScript initialColorMode={theme.config.initialColorMode}/> <Main/> <NextScript/> </body> </Html> ); }
Опять же, не стоит забывать об импорте:
import {ColorModeScript} from "@chakra-ui/react"; import {theme} from "./_app";
Давайте заменим стандартную индексную страницу Next.js на приглашение к входу в систему.
Перейдите к pages/index.tsx и замените его содержимое на следующее:
// pages/index.tsx import {Box, Button, Spinner, Text, VStack} from "@chakra-ui/react"; export default function Home() { return ( <Box m={8}> <VStack> <Text>You are not authenticated.</Text> <Button colorScheme="blue" onClick={() => console.log("Beep boop")}> Sign in </Button> </VStack> </Box> ); }
Запустите сервер разработки:
$ npx next dev
Откройте ваш любимый браузер и перейдите по адресу http://127.0.0.1:3000/. На экране должна появиться страница с сообщением «Вы не авторизованы» и кнопкой «Войти». При нажатии на кнопку в консоль должно быть выведено отладочное сообщение.
Отлично. На этом начальная настройка завершена.
В этом разделе мы установим Auth.js и займемся аутентификацией на основе учетных данных.
Перед началом работы с Auth.js установим Axios — простой HTTP-клиент на основе обещаний для браузера и Node.js. Эта библиотека позволит нам отправлять HTTP-запросы к нашему бэкенду с помощью элегантного и лаконичного синтаксиса.
Установите его с помощью NPM:
$ npm install axios@1.3.6
Двигаясь дальше, установите Auth.js:
$ npm install next-auth@4.22.1
Для корректной работы Auth.js сначала необходимо задать некоторые переменные окружения. В Next.js переменные окружения автоматически загружаются из .env.local корня проекта.
Создайте .env.local со следующим содержимым:
# .env.local NEXTAUTH_URL=http://127.0.0.1:3000/ NEXTAUTH_SECRET=verycomplexsecretkey NEXTAUTH_BACKEND_URL=http://127.0.0.1:8000/api/ NEXT_PUBLIC_BACKEND_URL=http://127.0.0.1:8000/api/
Далее необходимо создать обработчик динамических маршрутов и папку конфигураций Auth.js. Создайте папку auth в папке pages/api и файл […nextauth].js во вновь созданной папке.
pages/ ├── api/ │ └── auth/ │ └── [...nextauth].js ├── _app.tsx ├── _document.tsx └── index.tsx
Прежде чем приступить к работе с кодом, давайте поясним, как работают сессии Auth.js. Auth.js имеет два встроенных способа работы с сессиями:
Поскольку в качестве бэкенда мы используем Django, то придется воспользоваться вторым подходом. Недостатком этого подхода является утомительная передача аргументов и хранение accessToken
, refreshToken
и других чувствительных переменных в JWT-токене.
Вставьте следующее содержимое в […nextauth].js:
// pages/api/auth/[...nextauth].js import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import axios from "axios"; // These two values should be a bit less than actual token lifetimes const BACKEND_ACCESS_TOKEN_LIFETIME = 45 * 60; // 45 minutes const BACKEND_REFRESH_TOKEN_LIFETIME = 6 * 24 * 60 * 60; // 6 days const getCurrentEpochTime = () => { return Math.floor(new Date().getTime() / 1000); }; const SIGN_IN_HANDLERS = { "credentials": async (user, account, profile, email, credentials) => { return true; }, }; const SIGN_IN_PROVIDERS = Object.keys(SIGN_IN_HANDLERS); export const authOptions = { secret: process.env.AUTH_SECRET, session: { strategy: "jwt", maxAge: BACKEND_REFRESH_TOKEN_LIFETIME, }, providers: [ CredentialsProvider({ name: "Credentials", credentials: { username: {label: "Username", type: "text"}, password: {label: "Password", type: "password"} }, // The data returned from this function is passed forward as the // `user` variable to the signIn() and jwt() callback async authorize(credentials, req) { try { const response = await axios({ url: process.env.NEXTAUTH_BACKEND_URL + "auth/login/", method: "post", data: credentials, }); const data = response.data; if (data) return data; } catch (error) { console.error(error); } return null; }, }), ], callbacks: { async signIn({user, account, profile, email, credentials}) { if (!SIGN_IN_PROVIDERS.includes(account.provider)) return false; return SIGN_IN_HANDLERS[account.provider]( user, account, profile, email, credentials ); }, async jwt({user, token, account}) { // If `user` and `account` are set that means it is a login event if (user && account) { let backendResponse = account.provider === "credentials" ? user : account.meta; token["user"] = backendResponse.user; token["access_token"] = backendResponse.access; token["refresh_token"] = backendResponse.refresh; token["ref"] = getCurrentEpochTime() + BACKEND_ACCESS_TOKEN_LIFETIME; return token; } // Refresh the backend token if necessary if (getCurrentEpochTime() > token["ref"]) { const response = await axios({ method: "post", url: process.env.NEXTAUTH_BACKEND_URL + "auth/token/refresh/", data: { refresh: token["refresh_token"], }, }); token["access_token"] = response.data.access; token["refresh_token"] = response.data.refresh; token["ref"] = getCurrentEpochTime() + BACKEND_ACCESS_TOKEN_LIFETIME; } return token; }, // Since we're using Django as the backend we have to pass the JWT // token to the client instead of the `session`. async session({token}) { return token; }, } }; export default NextAuth(authOptions);
Примечания:
authorize()
.authOptions
и добавили CredentialsProvider
в его провайдеры
.CredentialsProvider
мы определили, какие поля должна содержать форма входа, и определили метод authorize()
, который передает учетные данные на бэкенд для их проверки.signIn()
, jwt()
и session()
. Обновление токена на бэкенде реализовано в колбэке jwt()
.Чтобы узнать больше об обратных вызовах Auth.js, ознакомьтесь с Auth.js Callbacks.
Наконец, оберните ваше приложение с помощью SessionProvider
в pages/_app.tsx следующим образом:
// pages/_app.tsx import type {AppProps} from "next/app"; import {SessionProvider} from "next-auth/react"; import {ChakraProvider, extendTheme} from "@chakra-ui/react"; export const theme = extendTheme({}); export default function App({Component, pageProps: {session, ...pageProps}}: AppProps) { return ( <SessionProvider session={session}> <ChakraProvider theme={theme}> <Component {...pageProps} /> </ChakraProvider> </SessionProvider> ); }
Не забывайте об импорте:
import {SessionProvider} from "next-auth/react";
Провайдер SessionProvider
обеспечит доступ к сессии через хук useSession()
.
Для внедрения типа Session
создайте в корне проекта новую папку с именем types. Затем добавьте в нее следующий файл с именем next-auth.d.ts.
Теперь давайте поработаем с представлениями.
Сначала измените свой pages/index.tsx следующим образом:
// pages/index.tsx import {useRouter} from "next/router"; import {signIn, useSession} from "next-auth/react"; import {Box, Button, Spinner, Text, VStack} from "@chakra-ui/react"; export default function Home() { const router = useRouter(); const {data: session, status} = useSession(); if (status == "loading") { return <Spinner size="lg"/>; } // If the user is authenticated redirect to `/profile` if (session) { router.push("profile"); return; } return ( <Box m={8}> <VStack> <Text>You are not authenticated.</Text> <Button colorScheme="blue" onClick={() => signIn(undefined, {callbackUrl: "/profile"})} > Sign in </Button> </VStack> </Box> ); }
Примечания:
useSession()
для получения сессии от SessionProvider
.Spinner
./profile
через useRouter()
.signIn()
.Далее создайте в папке pages новый файл с именем profile.tsx со следующим содержимым:
// pages/profile.tsx import {useState} from "react"; import {signOut, useSession} from "next-auth/react"; import {Box, Button, Code, HStack, Spinner, Text, VStack} from "@chakra-ui/react"; import axios from "axios"; export default function Home() { const {data: session, status} = useSession({required: true}); const [response, setResponse] = useState("{}"); const getUserDetails = async (useToken: boolean) => { try { const response = await axios({ method: "get", url: process.env.NEXT_PUBLIC_BACKEND_URL + "auth/user/", headers: useToken ? {Authorization: "Bearer " + session?.access_token} : {}, }); setResponse(JSON.stringify(response.data)); } catch (error) { setResponse(error.message); } }; if (status == "loading") { return <Spinner size="lg"/>; } if (session) { return ( <Box m={8}> <VStack> <Text>PK: {session.user.pk}</Text> <Text>Username: {session.user.username}</Text> <Text>Email: {session.user.email || "Not provided"}</Text> <Code> {response} </Code> </VStack> <HStack justifyContent="center" mt={4}> <Button colorScheme="blue" onClick={() => getUserDetails(true)}> User details (with token) </Button> <Button colorScheme="orange" onClick={() => getUserDetails(false)}> User details (without token) </Button> <Button colorScheme="red" onClick={() => signOut({callbackUrl: "/"})}> Sign out </Button> </HStack> </Box> ); } return <></>; }
Примечания:
useRouter()
и useSession()
так же, как и в предыдущем фрагменте кода.getUserDetails()
, который получает информацию о пользователе и отображает ее.signOut()
.Перезапустите сервер разработки Next:
$ npx next dev
Затем откройте свой любимый браузер и перейдите по адресу http://127.0.0.1:3000. Нажмите кнопку «Войти» и убедитесь, что вы перенаправлены на форму регистрации. Заполните форму и нажмите кнопку «Войти с учетными данными».
При успешном входе в систему вы будете перенаправлены на страницу профиля. Попробуйте получить информацию о пользователе, используя свой accessToken
.
В этом разделе мы настроим социальную аутентификацию с помощью Google. Интеграция других социальных провайдеров с Auth.js практически аналогична. Просто убедитесь, что ваш бэкенд Django работает, прежде чем переходить к фронтенду.
Не стесняйтесь пропустить этот раздел, если вас не интересует социальная аутентификация.
Во-первых, добавьте в .env.local две переменные окружения:
# .env.local # ... GOOGLE_CLIENT_ID=<your_google_client_id> GOOGLE_CLIENT_SECRET=<your_google_secret>
Обязательно замените <your_google_client_id>
и <your_google_secret>
на ваши реальные ключи. Помните, что ключи должны совпадать с ключами, указанными в core/settings.py.
Далее зарегистрируйте обработчик входа в систему Google в […nextauth].js:
// pages/api/auth/[...nextauth].js const SIGN_IN_HANDLERS = { // ... "google": async (user, account, profile, email, credentials) => { try { const response = await axios({ method: "post", url: process.env.NEXTAUTH_BACKEND_URL + "auth/google/", data: { access_token: account["id_token"] }, }); account["meta"] = response.data; return true; } catch (error) { console.error(error); return false; } } };
Единственное назначение этого обработчика — переслать id_token
на эндпоинт Django social. Все остальное — создание аккаунта, регистрацию пользователя и т.д. — Django берет на себя.
Затем добавьте GoogleProvider
в нижнюю часть массива providers
в […nextauth].js:
// pages/api/auth/[...nextauth].js export const authOptions = { // ... providers: [ // ... GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorization: { params: { prompt: "consent", access_type: "offline", response_type: "code" } } }), ], // ... };
Не забудьте импортировать GoogleProvider
в верхней части файла:
import GoogleProvider from "next-auth/providers/google";
Это все, что мы должны сделать.
Перед тестированием убедитесь, что ваш бэкенд Django запущен и доступен по URL, заданному в .env.local. После этого завершите процесс сервера разработки Next и запустите его снова:
$ npx next dev
Перейдите на сайт http://127.0.0.1:3000/ в вашем любимом браузере и нажмите на кнопку «Войти». Выберите «Войти с помощью Google» и проверьте, работает ли социальная аутентификация.
В этом руководстве мы успешно реализовали систему аутентификации Django REST и связали ее с Auth.js. Реализованная система поддерживает аутентификацию на основе учетных данных, а также социальную аутентификацию с помощью Google. Она построена таким образом, что в нее легко можно добавить других социальных провайдеров, таких как Twitter, GitHub и т.д.
Исходный код доступен в GitHub-репозитории django-rest-authjs.
authorize()
, либо создайте специальную страницу регистрации.При анализе данных часто требуется быстро найти абсолютное значение набора чисел. Для выполнения этой задачи…
Pydantic - это мощная библиотека проверки данных и управления настройками для Python, созданная для повышения…
Python предлагает набор библиотек, удовлетворяющих различные потребности в визуализации, будь то академические исследования, бизнес-аналитика или…
В Python для представления данных в двоичной форме можно использовать байты. Из этой статьи вы…
В этой статье рассказывается о том, что такое Werkzeug и как Flask использует его для…
При работе с датами часто возникает необходимость прибавлять к дате или вычитать из нее различные…