- PVSM.RU - https://www.pvsm.ru -
Эта статья будет интересна тем, кто особо не заморачивался, как устроена авторизация в бекенде, но хочет очень быстро въехать в тему. Мы не будем погружаться в самые недры реализации, но точно поймем как это работает и как прикрутить это на практике. Я буду использовать python и FastAPI, просто потому что так проще показать, но эти подходы работают и для других языков/фреймворков.
Это топ видов авторизации по API для бекенд сервисов. Конечно есть еще варианты, но эти - основа, которая встречается в 99% случаев.
Basic Auth — быстро, просто, но почти всегда плохая идея
Session — подходит для серверных HTML-приложений
JWT — лучший выбор для REST API и SPA, если правильно реализовать
OAuth2 — must-have для входа через сторонние сервисы, делегирования прав
Keycloak — оптимален, если нужен SSO, MFA, LDAP, Google Login и централизованное управление пользователями
Все что будет описано ниже, я разобрал в видео формате для твоего удобства! Выбирай подходящий тебе вид контента и изучай!
Обязательно изучи материал по теме
Посмотри демо пример, это репозиторий в котором я реализовал для тебя этот вид авторизации
Сделай домашнее задание из файлика tasks.md в этой ветке, например tasks.md [1]
Разбери возникшие вопросы с гуглом, или пиши мне в телегу
Итак для начала нам следует вспомнить некоторые понятия, которые помогут дальше говорить на одном языке.
Идентификация — это процесс, при котором пользователь представляется системе, т.е. заявляет, кто он есть.
Ключевые черты:
Это заявление личности, а не проверка
Само по себе не гарантирует, что вы тот, за кого себя выдаёте
Всегда предшествует аутентификации
Используется в:
Формы логина (username или email)
JWT — поле sub (subject) — это идентификатор
Какой то внешний идентификатор (например банковская карта, пропуск)
Аутентификация — это процесс проверки личности пользователя. Система должна убедиться, что вы действительно тот, за кого себя выдаёте.
Ключевые методы:
Пароль / Pin code
Токен / сертификат
Одноразовый код (OTP)
Биометрия (лицо, палец)
Авторизация — это процесс определения, какие действия разрешены пользователю после успешной аутентификации.
Ключевые формы:
Роли (admin, user, moderator)
Права (read, write, delete)
Scopes (в OAuth2)
ACL (access control lists)
🧠 Как легко запомнить:
Идентификация - это "покажи кто ты",
Аутентификация — это “докажи, что ты — это ты”,
Авторизация — “что тебе разрешено”
Еще одна штука нам потребуется, чтобы лучше друг друга понимать.
Base64 — это способ кодировать любые данные (текст или байты) в ASCII-символы, чтобы их можно было безопасно передавать по интернету (в заголовках, URL, JSON и т.п.).
Не защищает, не шифрует, просто делает байты пригодными для HTTP.
Как работает:
Преобразует бинарные данные в набор символов A-Z, a-z, 0-9, + и /.
Выход всегда строка, пригодная для HTTP и JSON.
Часто заканчивается на = (паддинг для выравнивания).
# Кодирование строки:
import base64
text = "hello:world"
encoded = base64.b64encode(text.encode()).decode()
print(encoded) # aGVsbG86d29ybGQ=
# Декодирование:
decoded = base64.b64decode(encoded).decode()
print(decoded) # hello:world
⚠️ Важно:
Base64 — не шифрование!
Любой может декодировать обратно. Это не безопасность, а удобство передачи.
Для защиты (например, в JWT) используется подпись, а не base64.
Все что нам достаточно тут знать - это то, что протокол HTTP работает по принципу клиент-сервер. Клиентское приложение формирует запрос и отправляет его на сервер, после чего сервер обрабатывает запрос, формирует ответ и передаёт его обратно клиенту.
У запросов есть заголовки (headers) и мы в них можем что то класть по принципу ключ-значение. Далее подробно мы посмотрим как и что мы отправляем.
Basic Auth — это самый простой способ аутентификации, при котором логин и пароль передаются в каждом HTTP-запросе в виде base64-кодированной строки.
Идеально, когда нужно просто и быстро, но никогда не используйте его в публичных приложениях без HTTPS.
Basic Auth — это минимализм в чистом виде.
Это не решение “на годы” — это способ “воткнуть логин за 30 секунд”.
Пользователь вводит логин и пароль
Эти данные кодируются в base64: username:password
Base64 не шифрует, а просто кодирует → нужен HTTPS
В каждом запросе отправляется заголовок:
Authorization: Basic YWRtaW46c2VjcmV0=
Сервер декодирует заголовок и проверяет логин/пароль вручную или через middleware
Middleware — это промежуточный слой, который обрабатывает запрос до (или после) основного обработчика запроса.
Настраивается за 1 минуту (например, в Nginx или FastAPI)
Не требует куки, базы сессий, генерации токенов
Стандарт HTTP с 1990-х, реализован во многих библиотеках
Даже после логина — логин и пароль уходят в каждом запросе
“Выйти” невозможно — только очистив кэш браузера или токен
Перехват трафика = кража пароля
Нет ролей, scopes, сессий
Нет revoke, логов, контроля, аналитики
✅ Подходит:
Админ-панели “для своих”
Внутренние инструменты (за VPN)
Быстрые MVP, тестовые API
❌ Не подходит:
Публичные веб-приложения
SPA и мобильные клиенты
Продакшн без HTTPS
Демо пример [2]
Документация [3]
from fastapi import FastAPI, Depends
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
@app.get("/secret-resource")
def read_secret(credentials: HTTPBasicCredentials = Depends(security)):
if credentials.username == "admin" and credentials.password == "secret":
return {"message": "Welcome!"}
return {"error": "Unauthorized"}
⚠️ Это наиболее частый сценарий использования basic auth
Демо пример [4]
Документация [5]
Nginx может сам проверять логин и пароль до того, как запрос попадёт в backend (например, FastAPI, Django и т.д.).
Это удобно, когда нужно:
Защитить dev-сервер, staging или внутренний API
Поставить “заглушку” на admin-панель
Не лезть в код приложения вообще
Пользователь заходит на защищённый URL
Браузер показывает окно ввода логина/пароля
Nginx проверяет их с помощью файла .htpasswd
Только после этого отдаёт доступ
Обязательно использовать HTTPS — иначе логин/пароль летят в открытом виде
Один и тот же логин/пароль у всех (без логики на стороне приложения)
Нет сессий, ролей, разграничения доступа — только "допущен или нет"
Демо пример [6]
Это старый, проверенный способ аутентификации, который широко используется в классических веб-приложениях (Django, Flask, Rails и др.)
Схема работы session based auth
Пользователь логинится — отправляет логин/пароль
→ POST /login с {"username": "...", "password": "..."}
Сервер проверяет их и создаёт сессию
→ Сохраняем в памяти или базе связь сессии с учеткой
Сервер присваивает сессии уникальный ID (обычно — случайная строка)
→ Генерируем session_id
Этот ID отправляется пользователю в cookie
→ например,
HTTP/1.1 200 OK
Set-Cookie: sessionid=abc123; HttpOnly; Path=/; Secure
При каждом следующем запросе браузер автоматически отправляет cookie
→ например
GET /profile HTTP/1.1
Host: example.com
Cookie: sessionid=abc123
Сервер по ID находит сессию и “узнаёт” пользователя
→ сверяем сессию в базе и вытаскиваем учетку к которой привязана сессия
Простота внедрения: легко реализуется на многих фреймворках
Безопасность: сессионный ID хранится только на сервере, токен не содержит чувствительную информацию
Простое управление: можно легко аннулировать сессии, контролировать время жизни
Меньшая нагрузка на клиент: вся логика аутентификации на сервере
Устойчивость к XSS-атакам: при правильной реализации с HttpOnly cookies
Хранение состояния: требует хранения сессий на сервере (память/БД/Redis)
Масштабируемость: сложнее распределять нагрузку между серверами
Проблемы с CORS: усложняется работа при кросс-доменных запросах
Уязвимость к CSRF-атакам: требуются дополнительные меры защиты
Производительность: дополнительные запросы к хранилищу сессий
Вот короткий пример реализации на FastAPI:
Этот пример показывает базовую реализацию сессионной аутентификации с использованием FastAPI и Redis для хранения сессий.
Ключевые моменты:
Сессионный ID генерируется как UUID и хранится в Redis с ограниченным временем жизни
Куки устанавливаются с флагами HttpOnly и SameSite для защиты
Реализованы основные эндпоинты: вход, выход и получение информации о текущем пользователе
При выходе сессия удаляется из Redis и куки очищаются
from fastapi import FastAPI, Depends, HTTPException, status, Response, Request
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from pydantic import BaseModel
import uuid
import redis
from typing import Optional
app = FastAPI()
security = HTTPBasic()
# Подключение к Redis
r = redis.Redis(host='localhost', port=6379, db=0)
SESSION_EXPIRE = 3600 # 1 час
# Модели данных
class User(BaseModel):
username: str
password: str
class UserInDB(User):
hashed_password: str
# Заглушка для базы данных пользователей
fake_users_db = {
"user1": {
"username": "user1",
"hashed_password": "password1" # В реальном приложении используйте хеширование паролей
}
}
# Проверка учетных данных
def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
user = fake_users_db.get(credentials.username)
if not user or user["hashed_password"] != credentials.password:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Неверные учетные данные",
headers={"WWW-Authenticate": "Basic"},
)
return user
# Получение пользователя по сессии
def get_user_by_session(request: Request):
session_id = request.cookies.get("session_id")
if not session_id:
return None
username = r.get(f"session:{session_id}")
if not username:
return None
return fake_users_db.get(username.decode())
# Маршруты
@app.post("/login")
def login(response: Response, user: User = Depends(get_current_user)):
# Создание сессии
session_id = str(uuid.uuid4())
r.setex(f"session:{session_id}", SESSION_EXPIRE, user["username"])
# Установка cookie
response.set_cookie(
key="session_id",
value=session_id,
httponly=True,
max_age=SESSION_EXPIRE,
samesite="lax",
secure=True # В production должно быть True
)
return {"message": "Успешный вход"}
@app.get("/me")
def read_user(user: Optional[dict] = Depends(get_user_by_session)):
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Требуется аутентификация"
)
return {"username": user["username"]}
@app.post("/logout")
def logout(response: Response, request: Request):
session_id = request.cookies.get("session_id")
if session_id:
r.delete(f"session:{session_id}")
response.delete_cookie(key="session_id")
return {"message": "Выход выполнен успешно"}
Пользователь отправляет логин и пароль
→ POST /login с {"username": "...", "password": "..."}
Сервер проверяет учётные данные
→ Сравнивает логин и пароль с логин-паролем из базы/хранилища.
Сервер создаёт JWT access token
→ С помощью функции из пункта 2. По сути генерирует специальную строку и не хранит ее, просто возвращает как результат метода
Токен возвращается пользователю
→ В теле ответа или HttpOnly cookie
Клиент сохраняет токен
→ В localStorage (❌ небезопасно) или в cookie (✅ безопасно)
LocalStorage — это хранилище в браузере, где можно сохранять данные в формате
ключ:значение
Дальнейшие запросы идут с токеном
→ В заголовке: Authorization: Bearer <token>
Сервер проверяет подпись и exp токена
→ Если всё ок — пользователь авторизован
Если exp прошел, значит токен более невалиден.
→ Возвращаемся на пункт 1.
Токен может быть любой, лишь бы ты реализовал логику процессинга. НО, обычно используется JWT токен, так как это стало “понятным стандартом” для реализации авторизации.
https://jwt.io/ [7] - оф дока, обязательно к посещению!
Демо пример [8]
JWT (JSON Web Token) — это токен, состоящий из трёх частей, разделённых точками header.payload.signature
Каждая часть:
Header — метаданные: тип токена и алгоритм подписи
Payload — данные (claims): кто вы, срок действия, роли и т.д.
Signature — цифровая подпись (проверка подлинности) </aside>
Передача токена осуществляется в заголовке HTTP Authentication: Bearer {your_token_here}
Base64 делает их безопасными для передачи по HTTP:
Без спецсимволов (
{},",:)Без пробелов, переносов
Только ASCII: удобно в URL, заголовках
пример токена
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30
Давай для начала рассмотрим какую информацию он может хранить и потом поймем как сделать свой токен.
Header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload:
{
"sub": "1234567890", # user uid
"name": "John Doe", # user name (например, для фронта)
"admin": true, # роль пользователя
"iat": 1516239022, # время когда токен был выпущен секунды начиная с 01-01-1970
"exp": 1716666000 # время когда токен "протухнет"
}
Signature:
Подпись. Это опциональная штука, можно и без нее, но тогда не проверить кто выпустил токен (см. ниже)
a-string-secret-at-least-256-bits-long
Пример генерации токена:
можешь запустить локально, установив пакет pyJWT
import jwt
from datetime import datetime, timedelta
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
def generate_token(data: dict):
payload = data.copy()
payload["exp"] = datetime.utcnow() + timedelta(minutes=15)
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
# Пример использования
token = generate_token({"sub": "user_id_123"})
print(token)
🔹 Что кладут в payload? (Так называемые claims)
|
Claim |
Назначение |
Обязательный? |
|---|---|---|
|
sub |
ID пользователя |
✅ Да |
|
exp |
Время истечения токена (timestamp) |
✅ Да |
|
iat |
Когда был выпущен |
⚠️ Желательно |
|
nbf |
“Не раньше чем” (not before) |
❌ Опционально |
|
iss |
Кто выдал токен (issuer) |
❌ Опционально |
|
aud |
Для кого токен предназначен (audience) |
❌ Опционально |
|
Пользовательские |
Например, role, email, scopes |
❌ Опционально |
Алгоритмы подписи: HS256 vs RS256
HS256 — симметричная подпись. Один секретный ключ. Просто, но не масштабируется.
RS256 — асимметричная. Частный ключ для подписи, публичный — для проверки. Лучше для микросервисов и OAuth2.
Ты можешь начать с HS256, а в полном проекте — перейти на RS256 или интеграцию с Keycloak, где это будет работать автоматически.
❌ Не ставят exp (и получают “вечные” токены)
❌ Добавляют в токен пароль или чувствительные данные
❌ Используют слишком короткий или слабый SECRET_KEY
❌ Отправляют токен без Bearer схемы в заголовке
❌ Не верифицируют подпись на сервере
Демо пример [9]
Refresh token используется для получения нового access token без повторной аутентификации пользователя. Его основная схема работы:
При авторизации клиент получает два токена:
Access token (короткоживущий, например 15-30 минут)
Refresh token (долгоживущий, например 7-30 дней)
Когда access token истекает:
Клиент отправляет refresh token на специальный endpoint (например, POST /refresh)
Сервер проверяет валидность refresh токена
При успешной проверке сервер генерирует новый access token и возвращает его клиенту
Опционально: генерирует новый refresh token (rotation strategy)
Схема запроса обновления:
POST /refresh
Content-Type: application/json
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ..."
}
Ответ:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...", // Опционально
"token_type": "Bearer",
"expires_in": 900
}
Структура: Могут быть JWT или просто случайные строки (UUID)
Хранение: Обязательно в базе данных или Redis на стороне сервера
Безопасность: Хранятся на стороне клиента в HttpOnly, Secure, SameSite=strict cookie или в защищенном хранилище
Срок жизни: Значительно дольше access токена, но имеет конечный срок
Создавайте уникальный refresh token для каждого устройства пользователя
Добавьте fingerprint устройства для дополнительной защиты
Используйте одноразовые refresh токены (rotation strategy)
Одним из недостатков JWT является сложность отзыва токенов, так как они по умолчанию валидны до истечения срока.
Существует несколько подходов к решению этой проблемы:
Blacklist отозванных токенов
# Пример хранения отозванных токенов в Redis
def revoke_token(token):
token_data = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
jti = token_data.get("jti", token_data.get("sub")) # уникальный ID токена
expiration = token_data["exp"] - int(datetime.utcnow().timestamp())
redis_client.setex(f"revoked:{jti}", expiration, "1")
def is_token_revoked(token):
token_data = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
jti = token_data.get("jti", token_data.get("sub"))
return redis_client.exists(f"revoked:{jti}")
Контроль через Refresh токены
Храните только refresh токены в базе данных
При логауте - удаляйте refresh токен из базы
Держите короткий срок жизни access токенов
Выпуск с версией/идентификатором пользовательской сессии
def generate_token(user_id, session_id):
return jwt.encode({
"sub": user_id,
"sid": session_id, # Идентификатор сессии
"exp": datetime.utcnow() + timedelta(minutes=15)
}, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token, active_sessions):
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
# Проверяем не только подпись, но и актуальность сессии
if payload["sid"] not in active_sessions.get(payload["sub"], []):
raise Exception("Token revoked")
return payload
Stateless - сервер не хранит сессии, что упрощает масштабирование
Самодостаточность - вся необходимая информация содержится в токене
Кросс-доменная работа - легко использовать в микросервисной архитектуре
Производительность - не требуется обращение к БД для проверки авторизации
Гибкость - можно включать различные claims (роли, права и т.д.)
Стандартизация - широко используемый формат с большим количеством библиотек
Разделение ответственности - возможность выделить авторизацию в отдельный сервис
Размер - JWT обычно больше, чем session ID (особенно с большим количеством claims)
Сложность отзыва - нет встроенного механизма отзыва (нужна доп. реализация)
Безопасность хранения - сложно безопасно хранить на клиенте
Утечка информации - payload не зашифрован, только закодирован в Base64
Усложнение при использовании refresh токенов - требует хранения состояния
Риск XSS-атак - при неправильном хранении в localStorage
Неизменяемость - нельзя изменить данные в токене без перевыпуска
Истекшие токены - до истечения срока клиент продолжает использовать неактуальный токен
|
Хранилище |
Access Token |
Refresh Token |
Комментарий |
|---|---|---|---|
|
HttpOnly Cookie |
✅ Хорошо |
✅ Лучший вариант |
Защита от XSS, уязвим к CSRF (нужна доп. защита) |
|
localStorage |
❌ Небезопасно |
❌ Очень небезопасно |
Уязвим к XSS-атакам |
|
sessionStorage |
⚠️ Относительно безопасно |
❌ Небезопасно |
Живет только во время сессии браузера |
|
Memory (JS переменная) |
✅ Хорошо |
⚠️ Не рекомендуется |
Исчезает при обновлении страницы |
|
IndexedDB |
⚠️ Зависит от реализации |
❌ Небезопасно |
Требует шифрования |
Рекомендуемый подход:
Access token: HttpOnly cookie или in-memory storage
Refresh token: Только HttpOnly, Secure, SameSite=strict cookie
Anti-CSRF токены
Генерируйте уникальный токен для каждой сессии
Проверяйте его при запросах, влияющих на состояние
Fingerprinting устройства
Привязывайте refresh токен к характеристикам устройства
Проверяйте соответствие при обновлении токена
SSO (Single Sign-On) — это механизм, при котором пользователь логинится один раз, чтобы получить доступ ко всем связанным системам, без повторной аутентификации.
🎯 Сам SSO — это поведение, а не технология.
А реализуется он через Keycloak, Okta, Azure AD и т.п.
User (пользователь) — хочет войти, знает свой логин и пароль
Service Provider (SP) — сайт, в который он заходит (например, GitLab)
Identity Provider (IdP) — сервис, который подтверждает личность (например, Keycloak, Google, Okta)
Заходишь на app1.company.com → логинишься
Переходишь на app2.company.com → уже залогинен
Переходишь в dashboard.partner.com [10] → тоже залогинен
→ без ввода пароля
Пользователь заходит на Service A
Его редиректят на IdP
Он логинится один раз
IdP возвращает токен или сессию
Пользователь получает доступ к Service A
При переходе на Service B, тот снова обращается к IdP → уже есть сессия → вход без пароля
SAML — старый, XML, часто в enterprise
OpenID Connect (OIDC) — надстройка над OAuth2, современный стандарт
Иногда — Kerberos (в Windows-доменных сетях)
Допустим, у тебя есть три приложения:
billing.domain.com [11]
docs.domain.com [12]
admin.domain.com [13]
С SSO:
Все они доверяют одному IdP (например, Keycloak)
Пользователь логинится один раз — и получает доступ ко всем трём
Удобно для пользователей (1 логин → много доступов)
Централизованный контроль безопасности
Идеально для корпоративной среды, микросервисов
Поддерживает MFA, LDAP, OAuth2, Google Login и др.
Одна точка отказа (если IdP не работает — никто не войдёт)
Нужно уметь правильно конфигурировать
Требует понимания протоколов (OIDC/SAML)
Демо пример [14]
OAuth 2.0 — это протокол авторизации, который позволяет приложению получить доступ к данным пользователя на другом сервисе, без передачи логина и пароля.
🎯 OAuth 2.0 ≠ не аутентификация, а доступ к ресурсам по доверенности.
«OAuth2 — это протокол, который позволяет приложениям действовать от имени пользователя, не зная его пароля. Всё через токены, всё под контролем.»
Ты логинишься на сайте через Google:
Этот сайт не получает твой пароль
Google показывает: “Это приложение хочет доступ к вашей почте”
Ты нажимаешь “Разрешить”
Приложение получает токен — и может читать твои письма (или что там запросили)
Resource Owner — пользователь (ты)
Client — приложение, которое хочет доступ (например, Zoom, Notion)
Authorization Server — кто выдает токен (например, Google)
Resource Server — API, к которому клиент хочет доступ (например, Gmail API)
Этапы:
Клиент (frontend) редиректит пользователя на Google:
<https://accounts.google.com/o/oauth2/auth?client_id=...&redirect_uri=>...
Пользователь логинится и разрешает доступ
Google редиректит обратно с code:
<https://your-app.com/callback?code=abc123>
Сервер (backend) обменивает code на access token (и опционально refresh token)
С этого момента клиент может использовать JWT-токен:
Authorization: Bearer <token>
По аналогии с JWT-токеном refresh-токен обновляет access-токен по истечению его срока жизни
Access Token — временный (часто 1 час), используется для запросов к API
Refresh Token — долговечный, используется для получения нового access token без логина
OAuth не занимается “кто ты”, он занимается “можно ли тебе это”.
Но если добавить OIDC (OpenID Connect) — появляется ID Token, и можно использовать OAuth2 как логин (SSO).
Не требует передавать логины/пароли другим сервисам
Можно ограничить доступ по scope (read, write, profile)
Работает с большинством крупных API
Основной протокол для “Войти через Google/Facebook/GitHub”
Сложная конфигурация (client_id, redirect_uri, state)
Есть много вариантов (flows): authorization code, client credentials, etc.
Если сделать неправильно — легко открыть уязвимость
Демо пример [15]
Keycloak — это готовая система управления пользователями и авторизацией, которая реализует протоколы OIDC (OpenID Connect) и OAuth2.0. Она предоставляет SSO, MFA, вход через сторонние сервисы и централизованный контроль доступа.
Keycloak — это всё в одном: логин, токены, роли, пользователи, OAuth2, OIDC, MFA и SSO.
Пользователь кликает “Войти” в одном из приложений
Браузер редиректится на Keycloak
Keycloak логинит пользователя (через форму, LDAP, Google и т.д.)
Возвращает пользователя с code обратно в приложение
Приложение обменивает code на access token, ID token, refresh token
Пользователь получает доступ к сервису
В другом приложении пользователь уже авторизован (SSO)
Keycloak — это Identity Provider (IdP)
Работает через OIDC (добавляет аутентификацию к OAuth2)
Выдаёт токены:
Access token (доступ к API)
ID token (информация о пользователе)
Refresh token (обновление токенов)
Поддерживает:
JWT (RS256 по умолчанию)
Google/GitHub/LDAP как сторонние IdP
MFA (2FA), политики доступа, роли, группы
Централизованная аутентификация
Полноценный SSO. Входит в одно — авторизован во всём
Поддержка стандартов: OIDC, OAuth2, SAML
Гибкость: UI логин, MFA, роли, политики, custom flows
Масштабируемо и стабильно: Отлично подходит для production / enterprise
Нужно разобраться с realмами, клиентами, маппингами
Требует сервера с Keycloak, либо Docker
Единая точка отказа (IdP): Если Keycloak упал — никто не войдёт
Сложно для маленьких проектов
✅ Подходит:
Микросервисная архитектура
Корпоративные платформы
Приложения с множеством клиентов и ролей
SSO через Google, GitHub, LDAP
❌ Не подходит:
Простейшие проекты без сложных пользователей
MVP с одним входом
Там, где нет инфраструктуры
Приложение регистрируется как "Client" в Keycloak
Пользователь логинится → возвращается code
FastAPI обменивает code на токены через HTTP-запрос:
import requests
def exchange_code_for_token(code: str):
res = requests.post("<https://keycloak/auth/realms/myrealm/protocol/openid-connect/token>", data={
"client_id": "myapp",
"client_secret": "secret",
"grant_type": "authorization_code",
"code": code,
"redirect_uri": "<https://myapp/callback>"
})
return res.json()
Ну и на последок шпаргалка по сравнениям видов авторизации
Надеюсь тебе было интересно, не забудь сделать домашние задания в каждой ветке! А так до встречи в следующей статье, пока!
Автор: takentui
Источник [16]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/428794
Ссылки в тексте:
[1] tasks.md: https://github.com/takentui/authorization_types/blob/fastapi-basic-auth/tasks.md
[2] Демо пример: https://github.com/takentui/authorization_types/tree/fastapi-basic-auth
[3] Документация: https://fastapi.tiangolo.com/advanced/security/http-basic-auth/?h=basic+auth
[4] Демо пример: https://github.com/takentui/authorization_types/tree/nginx-basic-auth
[5] Документация: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
[6] Демо пример: https://github.com/takentui/authorization_types/tree/cookie-auth
[7] https://jwt.io/: https://jwt.io/
[8] Демо пример: https://github.com/takentui/authorization_types/tree/jwt-auth
[9] Демо пример: https://github.com/takentui/authorization_types/tree/jwt-refresh-auth
[10] dashboard.partner.com: http://dashboard.partner.com
[11] billing.domain.com: http://billing.domain.com
[12] docs.domain.com: http://docs.domain.com
[13] admin.domain.com: http://admin.domain.com
[14] Демо пример: https://github.com/takentui/authorization_types/tree/oauth-2.0
[15] Демо пример: https://github.com/takentui/authorization_types/tree/keycloak
[16] Источник: https://habr.com/ru/articles/939662/?utm_source=habrahabr&utm_medium=rss&utm_campaign=939662
Нажмите здесь для печати.