← Назад к вопросам
Как работает авторизация по токену авторизации?
1.6 Junior🔥 131 комментариев
#Безопасность и аутентификация#API и интеграции
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает авторизация по токену авторизации
Авторизация по токену — это процесс проверки прав и разрешений пользователя, который уже прошёл аутентификацию. Токен содержит информацию о том, кто пользователь и какие действия ему разрешены.
Основной процесс
Этап 1: Аутентификация (получение токена)
Пользователь отправляет учётные данные:
POST /api/v1/auth/login
{"username": "john", "password": "secret123"}
Сервер проверяет пароль:
USER = найти в БД по username
if hash(password) == USER.password_hash:
TOKEN = создать JWT
return {"access_token": TOKEN, "expires_in": 3600}
Этап 2: Хранение токена (на клиенте)
// В браузере
localStorage.setItem('access_token', response.access_token);
// В мобильном приложении
SecureStorage.save('access_token', response.access_token);
Этап 3: Отправка токена с запросом
curl -X GET https://api.example.com/users/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
Этап 4: Проверка токена на сервере (авторизация)
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthCredentials
security = HTTPBearer()
def verify_token(credentials: HTTPAuthCredentials = Depends(security)):
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user_id = payload["sub"]
return user_id
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token"
)
@app.get("/users/me")
def get_current_user(user_id: int = Depends(verify_token)):
return {"user_id": user_id}
Структура JWT токена
JWT состоит из трёх частей, разделённых точками:
header.payload.signature
Header (заголовок):
{
"alg": "HS256",
"typ": "JWT"
}
Algorithm для подписи и тип токена.
Payload (данные):
{
"sub": 123,
"email": "john@example.com",
"name": "John Doe",
"roles": ["user", "admin"],
"permissions": ["read", "write"],
"iat": 1234567890,
"exp": 1234571490
}
данные о пользователе, его ролях, разрешениях и сроке действия.
Signature (подпись):
HMACSHA256(
base64(header) + "." + base64(payload),
secret_key
)
Криптографическая подпись для защиты от подделки.
Авторизация на основе ролей (RBAC)
Проверка того, что пользователь имеет требуемую роль.
def require_role(required_role: str):
def check_role(user_id: int = Depends(verify_token)):
user = get_user_from_db(user_id)
if required_role not in user.roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Insufficient permissions"
)
return user
return check_role
@app.delete("/users/{user_id}")
def delete_user(user_id: int, current_user = Depends(require_role("admin"))):
# Удалить пользователя
return {"status": "deleted"}
Авторизация на основе разрешений (PBAC)
Проверка наличия конкретного разрешения.
def require_permission(required_permission: str):
def check_permission(user_id: int = Depends(verify_token)):
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
if required_permission not in payload.get("permissions", []):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Permission denied"
)
return user_id
return check_permission
@app.post("/articles/{article_id}/publish")
def publish_article(
article_id: int,
user_id: int = Depends(require_permission("publish_articles"))
):
return {"status": "published"}
Жизненный цикл токена
1. Создание токена (при логине)
from datetime import datetime, timedelta
def create_access_token(user_id: int, expires_delta: timedelta = None):
to_encode = {"sub": user_id}
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(hours=1)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(
to_encode,
SECRET_KEY,
algorithm="HS256"
)
return encoded_jwt
2. Проверка токена (с каждым запросом)
def verify_token(token: str):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user_id = payload["sub"]
exp = payload["exp"]
# Проверка срока действия
if datetime.utcnow() > datetime.fromtimestamp(exp):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token expired"
)
return user_id
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token"
)
3. Refresh токена (когда истекает)
@app.post("/auth/refresh")
def refresh_token(refresh_token: str):
try:
payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
user_id = payload["sub"]
# Создать новый access token
new_access_token = create_access_token(user_id)
return {
"access_token": new_access_token,
"token_type": "bearer",
"expires_in": 3600
}
except jwt.InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid refresh token"
)
4. Отзыв токена (logout)
# Метод 1: Чёрный список токенов
blacklist = set() # На практике используй Redis
@app.post("/auth/logout")
def logout(token: str = Depends(get_token_from_header)):
blacklist.add(token)
return {"status": "logged out"}
# При проверке токена
def verify_token(token: str):
if token in blacklist:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token revoked"
)
# остальная проверка
Два типа токенов
Access Token (короткоживущий)
- Время жизни: 15 минут
- Использование: с каждым запросом
- Содержит: user_id, roles, permissions
- Риск: если украден, доступ только на 15 минут
Refresh Token (долгоживущий)
- Время жизни: 7 дней
- Использование: только для получения нового access token
- Содержит: user_id
- Преимущество: access token можно менять часто
Процесс:
1. Пользователь логинится → получает access_token (15 мин) + refresh_token (7 дней)
2. Отправляет запросы с access_token
3. Когда access_token истекает → использует refresh_token для получения нового
4. Refresh_token хранится безопасно (httpOnly cookie)
Безопасность
1. Защита токена
- Передавай только по HTTPS
- Хранить в httpOnly cookies (недоступны JavaScript)
- Никогда не логируй токены
- Ограничивай время жизни (exp)
2. Подпись токена
- Используй сильный алгоритм (HS256, RS256)
- Храни secret_key в переменной окружения
- Регулярно ротируй ключи
3. Проверка на сервере
# Всегда проверяй при каждом запросе
@app.get("/protected")
def protected_route(user_id: int = Depends(verify_token)):
return {"message": "Only authenticated users"}
Типичный flow аутентификации/авторизации
1. POST /auth/login {username, password}
→ Сервер проверяет пароль
→ Возвращает access_token + refresh_token
2. Клиент сохраняет токены
localStorage.setItem('access_token', token)
3. GET /api/protected -H "Authorization: Bearer token"
→ Сервер проверяет токен
→ Проверяет роли/разрешения
→ Возвращает данные или 403 Forbidden
4. Если access_token истекает:
POST /auth/refresh {refresh_token}
→ Сервер создаёт новый access_token
5. POST /auth/logout {token}
→ Добавить в blacklist
→ Клиент удаляет токены
Значение для System Analyst
System Analyst должен:
- Выбирать JWT для микросервисов и мобильных приложений
- Планировать время жизни токенов
- Обеспечивать механизм refresh и revocation
- Документировать требования безопасности
- Определять какие роли/разрешения нужны
- Планировать мониторинг скомпрометированных токенов
- Обучать команду best practices