Skip to content

API сервиса аутентификации и авторизации в приложение Твой ФФ!

License

Notifications You must be signed in to change notification settings

profcomff/auth-api

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

614a7e7 · Aug 27, 2024
Jun 27, 2024
Aug 27, 2024
Aug 20, 2024
Aug 6, 2024
Oct 19, 2022
May 26, 2024
Mar 12, 2023
Oct 19, 2022
Jul 23, 2024
Aug 10, 2024
Oct 19, 2022
Jul 13, 2023
Mar 26, 2023
Jun 27, 2024
Mar 11, 2023
Mar 12, 2023
Oct 19, 2022
Mar 26, 2023
Apr 5, 2024

Repository files navigation

auth-api

API сервиса аутентификации и авторизации в приложение Твой ФФ!

Схема работы Auth APUI

Auth Schema

Функционал

  1. Аутентификация и авторизация пользователей
  2. Управление доступами к ресурсам Твой ФФ
  3. Отправка пользовательских данных в Userdata API

Запуск

  1. Перейдите в папку проекта

  2. Создайте виртуальное окружение командой и активируйте его:

foo@bar:~$ python3 -m venv venv
foo@bar:~$ source ./venv/bin/activate  # На MacOS и Linux
foo@bar:~$ venv\Scripts\activate  # На Windows
  1. Установите библиотеки
foo@bar:~$ pip install -r requirements.txt
  • Бэкенд может запуститься без кластера Kafka. Просто не указывайте KAFKA_DSN в .env. Если вам нужна его логика, то тут находится инструкция по поднятию: https://github.com/profcomff/db-kafka
  1. Запускайте приложение!
foo@bar:~$ python -m auth_backend start

ENV-file description

  • DB_DSN – Адрес базы данных в фаормате postgresql://admin:admin@localhost:5432/dev
  • EMAIL – Адрес электронной почты (логин для входа) для отправки уведомлений по Email
  • EMAIL_PASS – Пароль от электронной почты
  • HOST – Хост для использования в шаблонах сообщений электронной почты
  • KAFKA_DSN - Адрес Kafka Cluster
  • KAFKA_USER_LOGIN_TOPIC_NAME - имя топика, куда Auth API пишет пользовательские данные при успешной авторизации
  • KAFKA_TIMEOUT - время, в течение которого kafka worker ждет пока новое сообщение отправится(не используется)
  • KAFKA_LOGIN - Логин в брокер сообщений Kafka
  • KAFKA_PASSWORD - Пароль в брокер сообщений Kafka
  • ENABLED_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

  • GOOGLE_REDIRECT_URL: str – URL адрес страницы для получения данных авторизации на нашем фронтэнде
  • GOOGLE_SCOPES: list[str] – Запрашиваемые у гугла права на управление аккаунтом, по умолчанию запрашивает данные пользователя
  • GOOGLE_CREDENTIALS: Json – Данные приложения Google, получить можно в Google Cloud Console

Physics

  • PHYSICS_REDIRECT_URL: str – см. секцию Google
  • PHYSICS_SCOPES: list[str] – см. секцию Google
  • PHYSICS_CREDENTIALS: Json – см. секцию Google

LK MSU

  • LKMSU_REDIRECT_URL – URL адрес страницы для получения данных авторизации на нашем фронтэнде

Yandex

  • YANDEX_REDIRECT_URL – URL адрес страницы для получения данных авторизации на нашем фронтэнде
  • YANDEX_CLIENT_ID - ID приложения, созданного в Яндексе
  • YANDEX_CLIENT_SECRET - Ключ для получения токена пользователя в Яндексе

MYMSU

  • MYMSU_REDIRECT_URL – см. секцию Yandex
  • MYMSU_CLIENT_ID - см. секцию Yandex
  • MYMSU_CLIENT_SECRET - см. секцию Yandex

Telegram

  • TELEGRAM_REDIRECT_URL – URL адрес страницы для получения данных авторизации на нашем фронтэнде
  • TELEGRAM_BOT_TOKEN - Токен бота приложения

Основные абстракции

  1. Пользователь - запись в таблице user, может иметь много методов входа, например, VK, email, LKMSU
  2. Скоуп - право на определенное действие над определенным ресурсом. Например timetable.event.update - право на изменение расписания в Timetable API
  3. Группа - запись в таблице Group. Может иметь родителя, в итоге группы образуют дерево(деревья). Группа имеет свои скоупы. Группы также косвенно имеет все скоупы своего родителя, которая в свою очередь имеет скоупы своего родителя и т.д.
  4. Сессия - сущность опредляющая доступ к аккаунту. Имеет токен, свои скоупы. Пользователь авторизуется и тем самым создает сессию. В нее можно поместить те права, которые есть у пользователя. Сессия заканчивается через какое то время и доступ становится невозможен, надо создать новую сессию.

Сценарий использования

Email: регистрация нового аккаунта

  1. Дернуть ручку POST /email/registrate . Вы передаете
{
 "email": "string", // Почта
 "password": "string" // Пароль
}
  1. На почту приходит письмо с линком на GET /email/approve?token='...', если по ней перейти то почта будет подтверждена и регистрацию можно считать завершенной.

Email: вход в аккаунт

  1. Дернуть ручку POST /email/login. там всего один вариант логина, никуда не денетесь
  2. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена.
  3. Вам придет токен, сохраняйте его куда нибудь, срок действия ограничен.

Email: Восстановление забытого пароля

  1. Дернуть ручку POST /email/reset/password/restore. Вы передаете
{"email": "string" // Почта}
  1. Вам придет письмо, где будет ссылка НА ФРОНТ(надо сделать это), в ссылке будет reset_token
  2. Токен надо передать в ручку POST /email/reset/password в заголовках, вместе с
{"new_password": ""}

и пароль будет изменен

Email: Изменение пароля

  1. Если пароль не забыт, а просто надо его поменять. Тогда в POST /email/reset/password/request передается токен авторизации, в теле вы передаете
{
"password": "string", // старый пароль
"new_password": "string" // новый пароль
}
  1. Отправляете запрос и всё, пароль изменен, вам придет письмо с уведомлением о смене пароляю

Email: Изменение адреса электронной почты

  1. Дернуть ручку POST /email/reset/email/request. Всего один вариант, передаете новое мыло в теле
{"email": "string" //Почта}

и токен атворизации в заголовках 2. На почту придет письмо с подтверждением почты, там будет токен подтверждения в query параметрах. Ссылка ведет на ручку GET пока что, но надо переделать, чтобы тоже вела на фронт.

Google/Physics: вход пользователя с аккаунтом Google

Все примеры написаны для Google аккаунта, для аккаунта physics.msu.ru средует делать запросы к /physics-msu вместо /google

  1. Получаем адрес для запроса на сервер Google: GET /google/auth_url
  2. Редиректим пользователя на этот url, пользователь входит в аккаунт и возвращается на страницу, которую можно узнать запросом GET /google/redirect_url
  3. Если Google не передал в ответе GET параметр error, передаем GET параметры страницы на сервер авториации в теле POST запроса в формате JSON: POST /google/login. Иначе возвращаем ошибку авторизации
  4. При успешном входе получаем token сессии. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена. Если сервер авторизации ответил ошибкой 401:
    1. запоминаем значение id_token из ответа.
    2. Предлагаем пользователю завести новый аккаунт нашего приложения, связанный с гуглом
  5. Если пользователь соглашается, делаем запрос с {"id_token": "<id-token>"} в теле на адрес POST /google/register. При успешном входе получаем token сессии, иначе показываем экран ошибки авторизации. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена.

Google/Physics: добавление аккаунта Google как второго метода входа

Все примеры написаны для Google аккаунта, для аккаунта physics.msu.ru средует делать запросы к /physics-msu вместо /google

  1. Получаем адрес для запроса на сервер Google: GET /google/auth_url
  2. Редиректим пользователя на этот url, пользователь входит в аккаунт и возвращается на страницу, которую можно узнать запросом GET /google/redirect_url
  3. Если Google не передал в ответе GET параметр error, передаем данные на сервер авториации: POST /google/register, указываем заголовок Authorization: <auth-token>. Иначе возвращаем ошибку авторизации
  4. При успешном входе получаем token сессии, иначе показываем экран ошибки авторизации

Telegram: добавление аккаунта Telegram как второго метода входа

  1. Получаем адрес обычным способом, перенаправляем туда пользователя
  2. После выдачи доступа пользователь попадает на redirect url с параметром #tgAuthResult=...
    1. На этой странице должен быть встроен виджет авторизации телеграмма, который преобразует #tgAuthResult=... в ?first_name=...&user_name=...
  3. Отослать данные из GET параметров в виде словаря на ручку GET /telegram/login
  4. При успешном входе получаем token сессии, иначе показываем экран ошибки авторизации

Созданиие группы

  1. Дернуть ручку POST /group, передать
{
"name": "string", // имя группы
"parent_id": "string", // айди предка группы(из него подтянутся скоупы)
"scopes": "string" // скуопы группы
}

Итоговые права участников группы будут равны сумме прав участников рожительской группы и прав текущей группы

Создание скоупсов

  1. У вас должен быть аккаунт с правом на создание скоупсов :)
  2. Получаете токен со скоупом auth.scope.create
  3. Идете с токеном на ручку POST /scope, отправляете его туда в заголовке и в теле отправляете
{
"name": "string", // имя скоупа(там должно быть две точки и три слова без пробелов)
"comment": "string" // комментарий
}
  1. Профит

Добавление скоупсов в группу

  1. Дернуть PATCH /group/{id}, передать
{"scopes": ["<scopes>"] // список, содержащий старые скоупы + новые. Ручка полностью заменит скоупы на переданные}

Узнать информацию о себе

  1. Дернуть ручку GET /me, передать в заголовках токен авторизации Ответ содержит поля
  • auth_methods - список доступных методов авторизации пользователя
  • session_scopes - скоупы текущей сессии
  • user_scopes - список доступных пользователю скоупов
  • indirect_groups - список групп в которых пользователь состоит косвенно(то есть родители групп, в которых он состоит непосредственно)
  • groups - список групп в которых пользователь состоит непосредственно
  • email - электронная почта пользователя
  • id - айди в Auth API

Добавление метода аутентификации

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

    • Все методы должны поддерживать минимум 2 варианта взаимодействия: регистрация нового пользователя (она же, добавление метода аутентификации существующему пользователю) и повторный вход.
    • Большинство внешних приложений (Google/Yandex/Telegram и др.) уже придумали все за вас и используют стандарт OAuth2 для авторизации внешних приложений, поэтому они очень похожи друг на друга и можно посомтреть примеры. Google авторизация уже реализована и можно почитать пути пользователя выше.
  2. Определитесь, какие методы нужны для работы с вашим методом авторизации.

    • По умолчанию есть 2 API ручки: /login – вход (повторный), и /register – первичная регистрация/добавление нового метода авторизации
    • Для OAuth2 авторизации и аутентификации также обязательно определены ручки /auth_url и /redirect_url – возвращают URL, куда пользователя должен перенаправить наш фронтенд для ввода логина и пароля на внешнем ресурсе, и URL, куда внешнее приложение перенаправит результат входа, соответственно
    • Вы можете определить и свои методы, но помните, что их нужно также поддержать и на фронтенде приложения. Обязательно опишите пошагово (а лучше нарисуйте схему в Miro или draw.io), как будут рабоать ваши методы со стороны пользователя/фронтенда
  3. Создайте новый файл в папке auth_backend/auth_plugins, создайте класс и отнаследуйте его

  4. Задайте классу описание, prefix и tags

    """Вход в приложение по аккаунту гугл"""
    prefix = '/google'
    tags = ['Google']

    • prefix используется как отправная точка для ваших методов. Ручка логина для метода авторизации с премиксом /myauth будет /myauth/login
    • Описание и теги используются для документирования кода. Зачастую без них непонятно, что вообще происходит. Не пропускайте их.
  5. Создайте основные методы

    • Помните, что все методы являются @staticmethod или @classmethod. То есть не принимают аргумент self (текущий объект), а принимают ничего или cls (текущий класс) соответственно
    • Ручки /login и /register имеют сигнатуры async def _login(...) и async def _register(...) соответственно
    • Ручка /login обязательно возвращает объект
      class UserSession(BaseDbModel):
    • Ручки /auth_url и /redirect_url методов OAuth2 обязательно возвращают оъект
      class UrlSchema(Base):
      url: str

Contributing

  • Основная информация по разработке наших приложений

  • Основная информация по разработке Auth API тут и тут