← Назад к вопросам
Как описывал метод проверки Bearer токена?
1.7 Middle🔥 251 комментариев
#REST API и HTTP#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Проверка Bearer токена: методы и реализация
Bearer токены — это стандартный механизм аутентификации в REST API. Это важная тема для backend разработчика.
Что такое Bearer токен
Bearer токен — это строка, которая передаётся в заголовке Authorization:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Слово Bearer означает носитель — приложение несёт этот токен в запросе.
Первый метод: Ручная проверка в каждом view
from flask import Flask, request, jsonify
from functools import wraps
app = Flask(__name__)
def get_bearer_token(request):
auth_header = request.headers.get('Authorization', '')
if not auth_header.startswith('Bearer '):
return None
return auth_header[7:]
def verify_token(token: str) -> bool:
valid_tokens = ['token123', 'token456']
return token in valid_tokens
@app.route('/api/protected', methods=['GET'])
def protected():
token = get_bearer_token(request)
if not token:
return jsonify({'error': 'No token'}), 401
if not verify_token(token):
return jsonify({'error': 'Invalid token'}), 401
return jsonify({'data': 'Secret info'})
Проблема: код повторяется везде. Нарушается DRY.
Второй метод: Декоратор для защиты (лучше)
from functools import wraps
def require_bearer_token(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = get_bearer_token(request)
if not token:
return jsonify({'error': 'Missing token'}), 401
if not verify_token(token):
return jsonify({'error': 'Invalid token'}), 401
return f(token=token, *args, **kwargs)
return decorated_function
@app.route('/api/protected')
@require_bearer_token
def protected(token):
return jsonify({'data': 'Secret info'})
@app.route('/api/admin')
@require_bearer_token
def admin(token):
return jsonify({'admin': True})
Логика проверки в одном месте.
Третий метод: JWT токены с PyJWT
Это производственный подход. JWT токены самовалидирующиеся — содержат подпись.
import jwt
from datetime import datetime, timedelta
SECRET_KEY = 'super-secret-key'
ALGORITHM = 'HS256'
def create_jwt_token(user_id: int, expires_in: int = 3600) -> str:
payload = {
'user_id': user_id,
'exp': datetime.utcnow() + timedelta(seconds=expires_in),
'iat': datetime.utcnow(),
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def verify_jwt_token(token: str) -> dict:
try:
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except jwt.ExpiredSignatureError:
raise jwt.InvalidTokenError('Token expired')
except jwt.InvalidTokenError as e:
raise jwt.InvalidTokenError(f'Invalid: {str(e)}')
def require_jwt(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = get_bearer_token(request)
if not token:
return jsonify({'error': 'Missing token'}), 401
try:
payload = verify_jwt_token(token)
except jwt.InvalidTokenError as e:
return jsonify({'error': str(e)}), 401
return f(payload=payload, *args, **kwargs)
return decorated_function
@app.route('/api/login', methods=['POST'])
def login():
user_id = 1
token = create_jwt_token(user_id)
return jsonify({'access_token': token, 'token_type': 'Bearer'})
@app.route('/api/profile')
@require_jwt
def get_profile(payload):
user_id = payload['user_id']
return jsonify({'user_id': user_id, 'name': 'Alice'})
Четвёртый метод: Django REST Framework
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
@api_view(['GET'])
@permission_classes([IsAuthenticated])
@authentication_classes([TokenAuthentication])
def protected_view(request):
return Response({'message': f'Hello {request.user}'})
Или для JWT:
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework_simplejwt.authentication import JWTAuthentication
@api_view(['GET'])
@permission_classes([IsAuthenticated])
@authentication_classes([JWTAuthentication])
def protected_view(request):
return Response({'user': request.user.username})
Пятый метод: FastAPI (современный)
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthCredentials
app = FastAPI()
security = HTTPBearer()
def verify_bearer_token(credentials: HTTPAuthCredentials = Depends(security)) -> str:
token = credentials.credentials
if not verify_token(token):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Invalid',
headers={'WWW-Authenticate': 'Bearer'},
)
return token
@app.get('/protected')
def protected(token: str = Depends(verify_bearer_token)):
return {'data': 'secret'}
Практический пример: Система с refresh токенами
from datetime import datetime, timedelta
import jwt
class TokenManager:
def __init__(self, secret_key: str):
self.secret_key = secret_key
self.algorithm = 'HS256'
def create_tokens(self, user_id: int):
now = datetime.utcnow()
access_payload = {
'user_id': user_id,
'type': 'access',
'exp': now + timedelta(minutes=15),
'iat': now,
}
refresh_payload = {
'user_id': user_id,
'type': 'refresh',
'exp': now + timedelta(days=30),
'iat': now,
}
access_token = jwt.encode(access_payload, self.secret_key, algorithm=self.algorithm)
refresh_token = jwt.encode(refresh_payload, self.secret_key, algorithm=self.algorithm)
return {
'access_token': access_token,
'refresh_token': refresh_token,
'token_type': 'Bearer',
}
def verify_token(self, token: str, token_type: str = 'access'):
try:
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
if payload.get('type') != token_type:
raise jwt.InvalidTokenError(f'Expected {token_type} token')
return payload
except jwt.ExpiredSignatureError:
raise jwt.InvalidTokenError('Token expired')
except jwt.InvalidTokenError as e:
raise jwt.InvalidTokenError(f'Invalid: {str(e)}')
manager = TokenManager(secret_key='my-secret-key')
tokens = manager.create_tokens(user_id=1)
payload = manager.verify_token(tokens['access_token'], token_type='access')
Типичные ошибки
1. Не проверять тип токена:
# Плохо
def verify_token(token):
return jwt.decode(token, key, algorithms=['HS256'])
# Хорошо
def verify_token(token, expected_type='access'):
payload = jwt.decode(token, key, algorithms=['HS256'])
if payload.get('type') != expected_type:
raise InvalidTokenError('Wrong type')
return payload
2. Не проверять истечение: JWT проверяет exp, но если custom токены — проверяй сам.
3. Передавать secret в коде:
# Плохо
SECRET = 'my-secret-key'
# Хорошо
SECRET = os.getenv('SECRET_KEY')
4. Не логировать попытки входа:
def require_jwt(f):
@wraps(f)
def decorated(*args, **kwargs):
token = get_bearer_token(request)
try:
payload = verify_jwt_token(token)
except Exception as e:
logger.warning(f'Auth failed: {e}')
return jsonify({'error': 'Invalid'}), 401
return f(payload=payload, *args, **kwargs)
return decorated
Итоговая рекомендация
- В production: используй JWT токены с refresh механизмом
- Всегда проверяй: expiration, тип, подпись
- Логируй попытки: для security audit
- Используй HTTPS: Bearer токены должны передаваться по HTTPS
- Храни секреты безопасно: в environment variables