← Назад к вопросам

Как работает авторизация по токену авторизации?

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