Пришли мне код авторизации
Ответ нейросети
26 сентября 2025 03:31
Отлично. Ниже приведён простой учебный пример реализации кода авторизации в рамках концепции OAuth 2.0 Authorization Code Grant. Это не продакшн-реализация, аDemonstration для понимания процесса: как генерируется код авторизации, как он валидируется и как обмениваться на токен доступа.
Ключевые моменты для понимания:
- Клиент запрашивает код авторизации у сервера авторизации (мы имитируем этот шаг через /authorize).
- Сервер выдаёт одноразовый код (authorization_code), который привязан к пользователю и клиенту, имеет срок годности и может быть использован один раз.
- Клиент затем обменивает код на access_token через эндпоинт /token, передавая client_id и client_secret для аутентификации клиента.
- В учебном примере хранение данных идёт в памяти (в словарях). В реальном мире данные нужно хранить в безопасной БД, использовать PKCE, защищённое хранение секретов и т.д.
Пример на Python с Flask
Что понадобится:
- Python 3.x
- Flask: установка через pip install Flask
Ниже код:
from flask import Flask, request, redirect, jsonify
import secrets
import time
from urllib.parse import urlencode
app = Flask(__name__)
# Простыми словами: в учебном примере показываем структуру данных
# Клиенты: client_id -> client_secret и допустимые redirect_uri
clients = {
"demo-client": {
"client_secret": "demo-secret",
"redirect_uris": ["http://localhost:8000/callback"]
}
}
# Хранилище кодов авторизации и токенов
authorization_codes = {} # code -> {user_id, client_id, redirect_uri, expires_at, used}
access_tokens = {} # token -> {user_id, client_id, expires_at}
def generate_code():
return secrets.token_urlsafe(32)
def generate_token():
return secrets.token_urlsafe(40)
def current_time():
return int(time.time())
@app.get("/authorize")
def authorize():
client_id = request.args.get("client_id")
redirect_uri = request.args.get("redirect_uri")
response_type = request.args.get("response_type")
state = request.args.get("state")
# Валидируем входящие параметры
if client_id not in clients:
return "Invalid client_id", 400
if redirect_uri not in clients[client_id]["redirect_uris"]:
return "Invalid redirect_uri", 400
if response_type != "code":
return "Unsupported response_type", 400
# Генерируем код авторизации
code = generate_code()
expires_at = current_time() + 600 # 10 минут жизни кода
authorization_codes[code] = {
"user_id": "user-1", # В реальном приложении берём текущего пользователя
"client_id": client_id,
"redirect_uri": redirect_uri,
"expires_at": expires_at,
"used": False
}
# Редиректим обратно к приложению-клиенту с кодом и state (если передан)
params = {"code": code}
if state:
params["state"] = state
redirect = redirect_uri + ("?" + urlencode(params))
return redirect
@app.post("/token")
def token():
grant_type = request.form.get("grant_type")
if grant_type != "authorization_code":
return jsonify({"error": "unsupported_grant_type"}), 400
code = request.form.get("code")
redirect_uri = request.form.get("redirect_uri")
client_id = request.form.get("client_id")
client_secret = request.form.get("client_secret")
# Валидируем клиента
if client_id not in clients:
return jsonify({"error": "invalid_client"}), 400
if clients[client_id]["client_secret"] != client_secret:
return jsonify({"error": "invalid_client"}), 400
# Валидируем код авторизации
if code not in authorization_codes:
return jsonify({"error": "invalid_grant"}), 400
rec = authorization_codes[code]
if rec["used"]:
return jsonify({"error": "invalid_grant"}), 400
if rec["expires_at"] < current_time():
return jsonify({"error": "invalid_grant"}), 400
if rec["client_id"] != client_id:
return jsonify({"error": "invalid_grant"}), 400
if rec["redirect_uri"] != redirect_uri:
return jsonify({"error": "invalid_grant"}), 400
# Помечаем код как использованный и выдаём токен
rec["used"] = True
access_token = generate_token()
expires_in = 3600 # 1 час
access_tokens[access_token] = {
"user_id": rec["user_id"],
"client_id": client_id,
"expires_at": current_time() + expires_in
}
return jsonify({
"access_token": access_token,
"token_type": "Bearer",
"expires_in": expires_in
})
if __name__ == "__main__":
app.run(debug=True)
Как работать с этим кодом (пошагово):
- Запустите файл на локальном компьютере. Убедитесь, что Flask установлен.
- Откройте браузер или используйте curl:
- Открыть запрос авторизации (пример): http://localhost:5000/authorize?client_id=demo-client&redirect_uri=http://localhost:8000/callback&response_type=code&state=xyz
- Это «вернёт» редирект на указанный redirect_uri с параметрами code и state. В учебном примере редирект будет работать только если вы перенаправляете на реальный сервер, который способен поймать этот запрос. В демонстрационных целях можно просто посмотреть код в ответе.
- Обмен кода на токен:
- Выполните POST-запрос на http://localhost:5000/token с форм-данными:
- grant_type=authorization_code
- code=<полученный код>
- redirect_uri=http://localhost:8000/callback
- client_id=demo-client
- client_secret=demo-secret
- В ответе получите access_token и срок его действия.
- Выполните POST-запрос на http://localhost:5000/token с форм-данными:
Безопасность и дальнейшее развитие (для понимания, а не для продакшена):
- Код должен быть однократного использования и иметь короткий срок жизни.
- Обычно применяют PKCE (для public clients) и строгую проверку redirect_uri.
- Реальный сервис хранит данные в базе данных и не хранит client_secret в коде сценария.
- Это базовый учебный пример. Для реального проекта используйте готовые решения и библиотеки, соответствующие вашей платформе.
Если хотите, могу привести аналогичный пример на другом языке (JavaScript/Node.js с Express, Java/Spring и т. п.) или добавить PKCE-реализацию и примеры тестирования curl/HTTP-запросов. Также можно адаптировать под ваш класс/уровень сложности — скажите, какой язык вам удобнее.
Понравился ответ?
Задай свой вопрос
Напиши любую задачу или вопрос, а нейросеть её решит



