https://github.com/profcomff/auth-api
API сервиса аутентификации и авторизации в приложение Твой ФФ!
https://github.com/profcomff/auth-api
auth-service
Last synced: 7 months ago
JSON representation
API сервиса аутентификации и авторизации в приложение Твой ФФ!
- Host: GitHub
- URL: https://github.com/profcomff/auth-api
- Owner: profcomff
- License: bsd-3-clause
- Created: 2022-09-17T20:04:20.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2025-04-06T22:58:06.000Z (7 months ago)
- Last Synced: 2025-04-06T23:25:28.983Z (7 months ago)
- Topics: auth-service
- Language: Python
- Size: 816 KB
- Stars: 16
- Watchers: 1
- Forks: 1
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# auth-api
API сервиса аутентификации и авторизации в приложение Твой ФФ!
[
](https://easycode.profcomff.com/templates/docker-fastapi/workspace?mode=manual¶m.Repository+URL=https://github.com/profcomff/auth-api.git¶m.Working+directory=auth-api)
## Схема работы Auth APUI

## Функционал
1) Аутентификация и авторизация пользователей
2) Управление доступами к ресурсам Твой ФФ
3) Отправка пользовательских данных в Userdata API
## Запуск
1) Перейдите в папку проекта
2) Создайте виртуальное окружение командой и активируйте его:
```console
foo@bar:~$ python3 -m venv venv
foo@bar:~$ source ./venv/bin/activate # На MacOS и Linux
foo@bar:~$ venv\Scripts\activate # На Windows
```
3) Установите библиотеки
```console
foo@bar:~$ pip install -r requirements.txt
```
- Бэкенд может запуститься без кластера Kafka. Просто не указывайте ``KAFKA_DSN`` в ``.env``. Если вам нужна его логика, то
тут находится инструкция по поднятию: ``https://github.com/profcomff/db-kafka``
4) Запускайте приложение!
```console
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`
Остальные параметры указаны [тут](https://github.com/profcomff/.github/wiki/%255Bbackend%255D-%25D0%259D%25D0%25B0%25D1%2581%25D1%2582%25D1%2580%25D0%25BE%25D0%25B9%25D0%25BA%25D0%25B8-%25D0%25BF%25D1%2580%25D0%25B8%25D0%25BB%25D0%25BE%25D0%25B6%25D0%25B5%25D0%25BD%25D0%25B8%25D1%258F)
### 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` . Вы передаете
```json
{
"email": "string", // Почта
"password": "string" // Пароль
}
```
3. На почту приходит письмо с линком на `GET /email/approve?token='...'`, если по ней перейти то почта будет подтверждена и регистрацию можно считать завершенной.
### Email: вход в аккаунт
1. Дернуть ручку `POST /email/login`. там всего один вариант логина, никуда не денетесь
2. В теле запроса есть scopes, это обязательный параметр. scopes - это лист айдишников, существующих в группах в которых вы состоите прямо или в группах, которые являются родителями ваших групп. Он может быть равен [], если вам не нужны права для этого токена.
3. Вам придет токен, сохраняйте его куда нибудь, срок действия ограничен.
### Email: Восстановление забытого пароля
1. Дернуть ручку `POST /email/reset/password/restore`. Вы передаете
```json
{"email": "string" // Почта}
```
3. Вам придет письмо, где будет ссылка НА ФРОНТ(надо сделать это), в ссылке будет reset_token
4. Токен надо передать в ручку `POST /email/reset/password` в заголовках, вместе с
```json
{"new_password": ""}
```
и пароль будет изменен
### Email: Изменение пароля
1. Если пароль не забыт, а просто надо его поменять. Тогда в `POST /email/reset/password/request` передается токен авторизации, в теле вы передаете
```json
{
"password": "string", // старый пароль
"new_password": "string" // новый пароль
}
```
3. Отправляете запрос и всё, пароль изменен, вам придет письмо с уведомлением о смене пароляю
### Email: Изменение адреса электронной почты
1. Дернуть ручку `POST /email/reset/email/request`. Всего один вариант, передаете новое мыло в теле
```json
{"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": ""}` в теле на адрес `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: `. Иначе возвращаем ошибку авторизации
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`, передать
```json
{
"name": "string", // имя группы
"parent_id": "string", // айди предка группы(из него подтянутся скоупы)
"scopes": "string" // скуопы группы
}
```
Итоговые права участников группы будут равны сумме прав участников рожительской группы и прав текущей группы
### Создание скоупсов
0. У вас должен быть аккаунт с правом на создание скоупсов :)
1. Получаете токен со скоупом auth.scope.create
2. Идете с токеном на ручку ` POST /scope`, отправляете его туда в заголовке и в теле отправляете
```json
{
"name": "string", // имя скоупа(там должно быть две точки и три слова без пробелов)
"comment": "string" // комментарий
}
```
4. Профит
### Добавление скоупсов в группу
1. Дернуть `PATCH /group/{id}`, передать
```json
{"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`, создайте класс и отнаследуйте его
- для legacy аутентификации от https://github.com/profcomff/auth-api/blob/1ce51bd532bd6f57c0abe922c7dd1a809d030723/auth_backend/auth_plugins/auth_method.py#L37
- для OAuth аутентификации от https://github.com/profcomff/auth-api/blob/1ce51bd532bd6f57c0abe922c7dd1a809d030723/auth_backend/auth_plugins/auth_method.py#L112
4. Задайте классу описание, `prefix` и `tags` https://github.com/profcomff/auth-api/blob/1ce51bd532bd6f57c0abe922c7dd1a809d030723/auth_backend/auth_plugins/google.py#L31-L34
- `prefix` используется как отправная точка для ваших методов. Ручка логина для метода авторизации с премиксом `/myauth` будет `/myauth/login`
- Описание и теги используются для документирования кода. Зачастую без них непонятно, что вообще происходит. Не пропускайте их.
5. Создайте основные методы
- Помните, что все методы являются `@staticmethod` или `@classmethod`. То есть не принимают аргумент `self` (текущий объект), а принимают ничего или `cls` (текущий класс) соответственно
- Ручки `/login` и `/register` имеют сигнатуры `async def _login(...)` и `async def _register(...)` соответственно
- Ручка `/login` обязательно возвращает объект https://github.com/profcomff/auth-api/blob/1ce51bd532bd6f57c0abe922c7dd1a809d030723/auth_backend/models/db.py#L117
- Ручки `/auth_url` и `/redirect_url` методов OAuth2 обязательно возвращают оъект https://github.com/profcomff/auth-api/blob/1ce51bd532bd6f57c0abe922c7dd1a809d030723/auth_backend/auth_plugins/auth_method.py#L115-L116
## Contributing
- Основная [информация](https://github.com/profcomff/.github/wiki/%255Bdev%255D-Backend-%25D1%2580%25D0%25B0%25D0%25B7%25D1%2580%25D0%25B0%25D0%25B1%25D0%25BE%25D1%2582%25D0%25BA%25D0%25B0) по разработке наших приложений
- Основная информация по разработке Auth API [тут](https://github.com/profcomff/auth-api/blob/main/CONTRIBUTING.md) и [тут](https://github.com/profcomff/.github/wiki/Сервис-авторизации)