API сервиса аутентификации и авторизации в приложение Твой ФФ!
- Аутентификация и авторизация пользователей
- Управление доступами к ресурсам Твой ФФ
- Отправка пользовательских данных в Userdata API
-
Перейдите в папку проекта
-
Создайте виртуальное окружение командой и активируйте его:
foo@bar:~$ python3 -m venv venv
foo@bar:~$ source ./venv/bin/activate # На MacOS и Linux
foo@bar:~$ venv\Scripts\activate # На Windows
- Установите библиотеки
foo@bar:~$ pip install -r requirements.txt
- Бэкенд может запуститься без кластера Kafka. Просто не указывайте
KAFKA_DSN
в.env
. Если вам нужна его логика, то тут находится инструкция по поднятию:https://github.com/profcomff/db-kafka
- Запускайте приложение!
foo@bar:~$ python -m auth_backend start
DB_DSN
– Адрес базы данных в фаорматеpostgresql://admin:admin@localhost:5432/dev
EMAIL
– Адрес электронной почты (логин для входа) для отправки уведомлений по EmailEMAIL_PASS
– Пароль от электронной почтыHOST
– Хост для использования в шаблонах сообщений электронной почтыKAFKA_DSN
- Адрес Kafka ClusterKAFKA_USER_LOGIN_TOPIC_NAME
- имя топика, куда Auth API пишет пользовательские данные при успешной авторизацииKAFKA_TIMEOUT
- время, в течение которого kafka worker ждет пока новое сообщение отправится(не используется)KAFKA_LOGIN
- Логин в брокер сообщений KafkaKAFKA_PASSWORD
- Пароль в брокер сообщений KafkaENABLED_AUTH_METHODS
- включенные методы авторизацииTOKEN_LENGTH
- длина отдаваемого токена при авторизацииSESSION_TIME_IN_DAYS
- время, через которое протухнет токенMAX_RETRIES
- максимальное кол-во ретраев при отправке письмаSTOP_MAX_DELAY
- максимальная задержка между попытками отправить письмоWAIT_MIN
,WAIT_MAX
- минимальное и максимальное время ожидания успешной отправки письмаEMAIL_DELAY_TIME_IN_MINUTES
- окно учёта писемEMAIL_DELAY_COUNT
- сколько писем можно отправить максимум в промежутке времениEMAIL_DELAY_TIME_IN_MINUTES
Остальные параметры указаны тут
GOOGLE_REDIRECT_URL: str
– URL адрес страницы для получения данных авторизации на нашем фронтэндеGOOGLE_SCOPES: list[str]
– Запрашиваемые у гугла права на управление аккаунтом, по умолчанию запрашивает данные пользователяGOOGLE_CREDENTIALS: Json
– Данные приложения Google, получить можно в Google Cloud Console
PHYSICS_REDIRECT_URL: str
– см. секцию GooglePHYSICS_SCOPES: list[str]
– см. секцию GooglePHYSICS_CREDENTIALS: Json
– см. секцию Google
LKMSU_REDIRECT_URL
– URL адрес страницы для получения данных авторизации на нашем фронтэнде
YANDEX_REDIRECT_URL
– URL адрес страницы для получения данных авторизации на нашем фронтэндеYANDEX_CLIENT_ID
- ID приложения, созданного в ЯндексеYANDEX_CLIENT_SECRET
- Ключ для получения токена пользователя в Яндексе
MYMSU_REDIRECT_URL
– см. секцию YandexMYMSU_CLIENT_ID
- см. секцию YandexMYMSU_CLIENT_SECRET
- см. секцию Yandex
TELEGRAM_REDIRECT_URL
– URL адрес страницы для получения данных авторизации на нашем фронтэндеTELEGRAM_BOT_TOKEN
- Токен бота приложения
- Пользователь - запись в таблице user, может иметь много методов входа, например, VK, email, LKMSU
- Скоуп - право на определенное действие над определенным ресурсом. Например
timetable.event.update
- право на изменение расписания в Timetable API - Группа - запись в таблице Group. Может иметь родителя, в итоге группы образуют дерево(деревья). Группа имеет свои скоупы. Группы также косвенно имеет все скоупы своего родителя, которая в свою очередь имеет скоупы своего родителя и т.д.
- Сессия - сущность опредляющая доступ к аккаунту. Имеет токен, свои скоупы. Пользователь авторизуется и тем самым создает сессию. В нее можно поместить те права, которые есть у пользователя. Сессия заканчивается через какое то время и доступ становится невозможен, надо создать новую сессию.
- Дернуть ручку
POST /email/registrate
. Вы передаете
{
"email": "string", // Почта
"password": "string" // Пароль
}
- На почту приходит письмо с линком на
GET /email/approve?token='...'
, если по ней перейти то почта будет подтверждена и регистрацию можно считать завершенной.
- Дернуть ручку
POST /email/login
. там всего один вариант логина, никуда не денетесь - В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена.
- Вам придет токен, сохраняйте его куда нибудь, срок действия ограничен.
- Дернуть ручку
POST /email/reset/password/restore
. Вы передаете
{"email": "string" // Почта}
- Вам придет письмо, где будет ссылка НА ФРОНТ(надо сделать это), в ссылке будет reset_token
- Токен надо передать в ручку
POST /email/reset/password
в заголовках, вместе с
{"new_password": ""}
и пароль будет изменен
- Если пароль не забыт, а просто надо его поменять. Тогда в
POST /email/reset/password/request
передается токен авторизации, в теле вы передаете
{
"password": "string", // старый пароль
"new_password": "string" // новый пароль
}
- Отправляете запрос и всё, пароль изменен, вам придет письмо с уведомлением о смене пароляю
- Дернуть ручку
POST /email/reset/email/request
. Всего один вариант, передаете новое мыло в теле
{"email": "string" //Почта}
и токен атворизации в заголовках 2. На почту придет письмо с подтверждением почты, там будет токен подтверждения в query параметрах. Ссылка ведет на ручку GET пока что, но надо переделать, чтобы тоже вела на фронт.
Все примеры написаны для Google аккаунта, для аккаунта physics.msu.ru средует делать запросы к /physics-msu
вместо /google
- Получаем адрес для запроса на сервер Google:
GET /google/auth_url
- Редиректим пользователя на этот url, пользователь входит в аккаунт и возвращается на страницу, которую можно узнать запросом
GET /google/redirect_url
- Если Google не передал в ответе GET параметр
error
, передаем GET параметры страницы на сервер авториации в теле POST запроса в формате JSON:POST /google/login
. Иначе возвращаем ошибку авторизации - При успешном входе получаем
token
сессии. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена. Если сервер авторизации ответил ошибкой 401:- запоминаем значение id_token из ответа.
- Предлагаем пользователю завести новый аккаунт нашего приложения, связанный с гуглом
- Если пользователь соглашается, делаем запрос с
{"id_token": "<id-token>"}
в теле на адресPOST /google/register
. При успешном входе получаемtoken
сессии, иначе показываем экран ошибки авторизации. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена.
Все примеры написаны для Google аккаунта, для аккаунта physics.msu.ru средует делать запросы к /physics-msu
вместо /google
- Получаем адрес для запроса на сервер Google:
GET /google/auth_url
- Редиректим пользователя на этот url, пользователь входит в аккаунт и возвращается на страницу, которую можно узнать запросом
GET /google/redirect_url
- Если Google не передал в ответе GET параметр
error
, передаем данные на сервер авториации:POST /google/register
, указываем заголовокAuthorization: <auth-token>
. Иначе возвращаем ошибку авторизации - При успешном входе получаем
token
сессии, иначе показываем экран ошибки авторизации
- Получаем адрес обычным способом, перенаправляем туда пользователя
- После выдачи доступа пользователь попадает на redirect url с параметром #tgAuthResult=...
- На этой странице должен быть встроен виджет авторизации телеграмма, который преобразует #tgAuthResult=... в ?first_name=...&user_name=...
- Отослать данные из GET параметров в виде словаря на ручку
GET /telegram/login
- При успешном входе получаем
token
сессии, иначе показываем экран ошибки авторизации
- Дернуть ручку
POST /group
, передать
{
"name": "string", // имя группы
"parent_id": "string", // айди предка группы(из него подтянутся скоупы)
"scopes": "string" // скуопы группы
}
Итоговые права участников группы будут равны сумме прав участников рожительской группы и прав текущей группы
- У вас должен быть аккаунт с правом на создание скоупсов :)
- Получаете токен со скоупом auth.scope.create
- Идете с токеном на ручку
POST /scope
, отправляете его туда в заголовке и в теле отправляете
{
"name": "string", // имя скоупа(там должно быть две точки и три слова без пробелов)
"comment": "string" // комментарий
}
- Профит
- Дернуть
PATCH /group/{id}
, передать
{"scopes": ["<scopes>"] // список, содержащий старые скоупы + новые. Ручка полностью заменит скоупы на переданные}
- Дернуть ручку
GET /me
, передать в заголовках токен авторизации Ответ содержит поля
auth_methods
- список доступных методов авторизации пользователяsession_scopes
- скоупы текущей сессииuser_scopes
- список доступных пользователю скоуповindirect_groups
- список групп в которых пользователь состоит косвенно(то есть родители групп, в которых он состоит непосредственно)groups
- список групп в которых пользователь состоит непосредственноemail
- электронная почта пользователяid
- айди в Auth API
-
Продумайте, какой путь должен совершить пользователь, чтобы войти в сервис с использованием вашего метода аутентификации
- Все методы должны поддерживать минимум 2 варианта взаимодействия: регистрация нового пользователя (она же, добавление метода аутентификации существующему пользователю) и повторный вход.
- Большинство внешних приложений (Google/Yandex/Telegram и др.) уже придумали все за вас и используют стандарт OAuth2 для авторизации внешних приложений, поэтому они очень похожи друг на друга и можно посомтреть примеры. Google авторизация уже реализована и можно почитать пути пользователя выше.
-
Определитесь, какие методы нужны для работы с вашим методом авторизации.
- По умолчанию есть 2 API ручки:
/login
– вход (повторный), и/register
– первичная регистрация/добавление нового метода авторизации - Для OAuth2 авторизации и аутентификации также обязательно определены ручки
/auth_url
и/redirect_url
– возвращают URL, куда пользователя должен перенаправить наш фронтенд для ввода логина и пароля на внешнем ресурсе, и URL, куда внешнее приложение перенаправит результат входа, соответственно - Вы можете определить и свои методы, но помните, что их нужно также поддержать и на фронтенде приложения. Обязательно опишите пошагово (а лучше нарисуйте схему в Miro или draw.io), как будут рабоать ваши методы со стороны пользователя/фронтенда
- По умолчанию есть 2 API ручки:
-
Создайте новый файл в папке
auth_backend/auth_plugins
, создайте класс и отнаследуйте его- для legacy аутентификации от
- для OAuth аутентификации от
-
Задайте классу описание,
prefix
иtags
auth-api/auth_backend/auth_plugins/google.py
Lines 31 to 34 in 1ce51bd
prefix
используется как отправная точка для ваших методов. Ручка логина для метода авторизации с премиксом/myauth
будет/myauth/login
- Описание и теги используются для документирования кода. Зачастую без них непонятно, что вообще происходит. Не пропускайте их.
-
Создайте основные методы
- Помните, что все методы являются
@staticmethod
или@classmethod
. То есть не принимают аргументself
(текущий объект), а принимают ничего илиcls
(текущий класс) соответственно - Ручки
/login
и/register
имеют сигнатурыasync def _login(...)
иasync def _register(...)
соответственно - Ручка
/login
обязательно возвращает объектauth-api/auth_backend/models/db.py
Line 117 in 1ce51bd
- Ручки
/auth_url
и/redirect_url
методов OAuth2 обязательно возвращают оъектauth-api/auth_backend/auth_plugins/auth_method.py
Lines 115 to 116 in 1ce51bd
- Помните, что все методы являются
-
Основная информация по разработке наших приложений