OAuth2 для разработчиков
Для кого этот раздел
В данном разделе приведена информация для разработчиков сервиса Auth-movies.
Intro
Все, что необходимо для работы с OAuth2 находится в папке src/movies_auth/app/oauth2
.
Requirements
Используется библиотека authlib
Конфиги провайдеров
Настройки OAuth провайдеров хранятся в файлах .env
в папке .envs
. Рассмотрим подробнее
структуру настроек на примере одного из провайдеров:
YANDEX_CLIENT_ID=c95621
YANDEX_CLIENT_SECRET=s389752f
YANDEX_OAUTH__AUTHORIZE_URL=https://oauth.yandex.ru/authorize
YANDEX_OAUTH__ACCESS_TOKEN_URL=https://oauth.yandex.ru/token
YANDEX_OAUTH__API_BASE_URL=https://login.yandex.ru
YANDEX_OAUTH__USERINFO_URL=info
client_id
и secret
. Имя переменной окружения
для этих параметров формируется по маске EXAMPLE_CLIENT_ID
, EXAMPLE_SECRET
,
где EXAMPLE
- это имя провайдера.
Warning
Библиотека authlib будет использовать имя EXAMPLE
как атрибут экземпляра класса провайдера
Затем следует блок переменных с префиксом EXAMPLE_OAUTH__
- эти настройки будут преобразованы
в словарь в объекте settings
:
{
'yandex_oauth': {
'authorize_url': 'https://oauth.yandex.ru/authorize',
'access_token_url': 'https://oauth.yandex.ru/token',
'api_base_url': 'https://login.yandex.ru',
'userinfo_url': 'info'
}
}
settings
следующим образом:
# src/settings.py
class BaseOAuthProvider(BaseModel):
authorize_url: str
access_token_url: str
api_base_url: str
userinfo_url: str
class Settings(BaseSettings):
PROJECT_NAME: str = "movies_auth"
SECRET_KEY: str
...
YANDEX_OAUTH: BaseOAuthProvider
Создание адаптера для провайдера
Каждый провайдер имеет свои уникальные настройки, начиная с адреса api, заканчивая местом
расположения access_token
в запросе. Работа с провайдерами реализована через адаптеры.
Для примера рассмотрим адаптер GoogleOAuthProvider
:
# src/movies_auth/app/oauth2/base.py
@dataclass
class GoogleOAuthProvider(BaseOAuthProvider):
name: str = OAuthProviders.google
client_kwargs: dict = field(
default_factory=lambda: {
"scope": "https://www.googleapis.com/auth/userinfo.email "
"https://www.googleapis.com/auth/userinfo.profile"
}
)
def get_social_account(self) -> SocialAccount | None:
user_info = self.get_user_info()
if user_info:
return SocialAccount(
id=user_info["id"],
email=user_info["email"],
login=user_info["email"],
name=user_info["given_name"],
)
return None
BaseOAuthProvider
. Имя нового провайдера нужно указать в классе OAuthProviders
:
# src/movies_auth/app/oauth2/base.py
@dataclass(slots=True, frozen=True)
class OAuthProviders:
yandex = "yandex"
mail = "mail"
google = "google"
На что следует обратить внимание при создании адаптера:
-
Имя провайдера: оно формируется из имени настроек
EXAMPLE_CLIENT_ID
. Для провайдера Google, настройка называетсяGOOGLE_CLIENT_ID
, значит имя должно бытьgoogle
. -
Получение данных пользователя выполняется в методе
get_user_info
базового классаBaseOAuthProvider
(метод может быть переопределен в адаптере):@dataclass class BaseOAuthProvider: ... def get_user_info(self) -> dict: r = self._client.get(self.userinfo_endpoint) return r.json()
-
Адаптер должен содержать метод
get_social_account
, который возвращает экземпляр классаSocialAccount
. -
Реквизит
client_kwargs
может содержать уникальные настройки, требуемые для провайдера. Например, для google требуется указатьscope
(разрешения), а для mail требуется указать место расположенияaccess_token
:@dataclass class MailOAuthProvider(BaseOAuthProvider): name: str = OAuthProviders.mail client_kwargs: dict = field(default_factory=lambda: {"token_placement": "uri"})
Регистрация провайдера
Для того чтобы провайдер начал действовать, его нужно зарегистрировать в приложении.
Сначала нужно создать экземпляр провайдера в файле src/movies_auth/app/oauth2/__init__.py
:
# src/movies_auth/app/oauth2/__init__.py
from app.oauth2 import base
oauth_manager = base.OAuthManager()
yandex_oauth = base.YandexOAuthProvider()
mail_oauth = base.MailOAuthProvider()
google_oauth = base.GoogleOAuthProvider()
create_app()
нужно зарегистрировать нового провайдера:
# src/movies_auth/app/__init__.py
from app.oauth2 import oauth_manager, yandex_oauth, mail_oauth, google_oauth
def create_app():
app = Flask(__name__)
app.config.from_object(settings)
oauth_manager.init_app(app, cache=redis_db)
oauth_manager.register_provider(yandex_oauth)
oauth_manager.register_provider(mail_oauth)
oauth_manager.register_provider(google_oauth)