/code, чтобы получить код авторизации
Ответ нейросети
02 сентября 2025 01:53
Задача: получить код авторизации в рамках безопасного учебного примера (OAuth 2.0 Authorization Code Flow). Ниже приведено подробное решение с пошаговыми объяснениями и примером кода на Python с использованием Flask. Это учебный пример, который демонстрирует, как получить код авторизации, а затем обменять его на токен доступа.
Что именно делает данный код
- Формирует ссылку на авторизацию у поставщика OAuth.
- Перенаправляет пользователя на страницу входа у поставщика.
- Получает код авторизации по редиректу обратно на локальный сервер.
- Обменяет полученный код на токен доступа (и, при желании, на refresh-токен).
- Пример рассчитан на PKCE (рекомендуется для публичных клиентов, например, мобильных приложений). В качестве учебной демонстрации PKCE включён.
Важно: замени все параметрические значения (URL-адреса, client_id, client_secret и т. п.) на данные твоего тестового провайдера OAuth. Не публикуй реальные секреты.
Шаги перед запуском
- Зарегистрируй приложение у провайдера OAuth и зафиксируй:
- authorization_endpoint (адрес авторизации)
- token_endpoint (адрес обмена кода на токен)
- client_id
- (при PKCE) возможность использовать code_challenge и code_verifier
- redirect_uri, например http://localhost:5000/callback
- Установи зависимости:
- Python 3.x
- pip install Flask requests
Пример кода (Python + Flask)
# oauth_code_flow.py
# Учебный пример получения кода авторизации и обмена на токен (OAuth 2.0 Authorization Code Flow с PKCE)
import os
import secrets
import hashlib
import base64
import requests
from urllib.parse import urlencode
from flask import Flask, redirect, request
# Где разместить параметры OAuth провайдера (замени на свои)
AUTHORIZATION_ENDPOINT = "https://provider.example.com/oauth2/authorize"
TOKEN_ENDPOINT = "https://provider.example.com/oauth2/token"
CLIENT_ID = "YOUR_CLIENT_ID"
# При PKCE клиент без секрета не обязан указывать client_secret (для публичных клиентов)
CLIENT_SECRET = "YOUR_CLIENT_SECRET" # опционально, если требуется
REDIRECT_URI = "http://localhost:5000/callback"
SCOPE = "read profile" # требуемые разрешения
USE_PKCE = True # включаем PKCE
app = Flask(__name__)
# Глобальные переменные для хранения состояния между запросами
code_verifier = None
state_value = None
def generate_pkce_pair():
# Код-верификатор (code_verifier) — случайная строка от 43 до 128 символов
verifier = base64.urlsafe_b64encode(os.urandom(32)).rstrip(b"=").decode("ascii")
# Код-Challenge — SHA256(verifier), затем кодируем в URL-safe base64
challenge = base64.urlsafe_b64encode(
hashlib.sha256(verifier.encode("ascii")).digest()
).rstrip(b"=").decode("ascii")
return verifier, challenge
@app.route("/login")
def login():
global code_verifier, state_value
state_value = secrets.token_urlsafe(16) # защита от CSRF
code_verifier = None
code_challenge = None
query_params = {
"response_type": "code",
"client_id": CLIENT_ID,
"redirect_uri": REDIRECT_URI,
"scope": SCOPE,
"state": state_value
}
if USE_PKCE:
code_verifier, code_challenge = generate_pkce_pair()
query_params["code_challenge"] = code_challenge
query_params["code_challenge_method"] = "S256"
# Собираем URL для перехода на страницу авторизации
auth_url = f"{AUTHORIZATION_ENDPOINT}?{urlencode({k: v for k, v in query_params.items() if v})}"
return redirect(auth_url)
def exchange_code_for_token(code):
# Обмен кода на токен
data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
"client_id": CLIENT_ID
}
if USE_PKCE and code_verifier:
data["code_verifier"] = code_verifier
# Если нужен client_secret (для конфиденциальных клиентов)
if not USE_PKCE and CLIENT_SECRET:
data["client_secret"] = CLIENT_SECRET
headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(TOKEN_ENDPOINT, data=data, headers=headers)
return response.json(), response.status_code
@app.route("/callback")
def callback():
global state_value
code = request.args.get("code")
state = request.args.get("state")
if state_value is not None and state != state_value:
return "State mismatch. Возможная атака CSRF.", 400
if not code:
return "No authorization code found in the callback.", 400
token_response, status = exchange_code_for_token(code)
if status != 200:
return f"Token request failed: {token_response}", status
# В учебном примере просто покажем токены в ответе
return (
f"Token response: {token_response}"
)
if __name__ == "__main__":
# Запуск локального сервера: http://localhost:5000/login
app.run(host="0.0.0.0", port=5000, debug=True)
Как это работает (пошагово)
- В браузере посетишь http://localhost:5000/login
- генерируется state и (при PKCE) code_challenge, сохраняются verifier и challenge для последующего обмена;
- формируется URL авторизации и браузер перенаправляется на страницу входа у провайдера.
- Пользователь вводит учётку и авторизуется у провайдера.
- Поставщик OAuth редиректит обратно на REDIRECT_URI, например http://localhost:5000/callback?code=AUTH_CODE&state=...
- В /callback код авторизации извлекается, проверяется совпадение state, затем код отправляется на token_endpoint для обмена на access_token (и при необходимости refresh_token).
- Сервер возвращает результат обмена (в учебном виде видно содержание ответа от провайдера).
Дополнительные пояснения
- PKCE: защищает кодовый поток от перехвата на открытых каналах. Для мобильных/клиентов без секретов PKCE почти обязательно. В примере мы генерируем code_verifier и code_challenge и передаём их в запросах.
- Без PKCE: можно обойтись без code_verifier и code_challenge, но тогда чаще нужен client_secret на этапе обмена токена. Этот сценарий применим только к конфиденциальным клиентам (серверным приложениям) и требует надёжного хранения секрета.
- Безопасность: не публикуй реальные client_secret в клиентском коде. Для учебных целей PKCE убирает необходимость секрета на клиенте.
Если хочешь, могу привести аналогичный пример на Node.js (Express) или на другом языке, и адаптировать под конкретного провайдера OAuth (например, Google, GitHub, Microsoft и т. д.). Также могу упростить пример до минимального варианта без Flask — просто с HTTP-сервером и ручным вводом кода, если такой формат удобнее.
Понравился ответ?
Задай свой вопрос
Напиши любую задачу или вопрос, а нейросеть её решит



