Flask - отправить JSON данные клиенту перед перенаправлением с помощью make_request - PullRequest
1 голос
/ 30 марта 2020

У меня есть этот URL обратного вызова, который имеет перенаправление:

@spotify_auth_bp.route("/callback", methods=['GET', 'POST'])
def spotify_callback():

    SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"

    CLIENT_ID =   os.environ.get('SPOTIPY_CLIENT_ID')
    CLIENT_SECRET = os.environ.get('SPOTIPY_CLIENT_SECRET')
    REDIRECT_URI = os.environ.get('SPOTIPY_REDIRECT_URI')

    auth_token = request.args['code']

    code_payload = {
        "grant_type": "authorization_code",
        "code": auth_token,
        "redirect_uri": REDIRECT_URI,
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
    }

    post_request = requests.post(SPOTIFY_TOKEN_URL, data=code_payload)

    # Auth Step 5: Tokens are Returned to Application
    response_data = json.loads(post_request.text)

    access_token = response_data["access_token"]
    refresh_token = response_data["refresh_token"]
    token_type = response_data["token_type"]
    expires_in = response_data["expires_in"]

    token_info = {'access_token': access_token,
                  'refresh_token': refresh_token,
                  'token_type': token_type,
                  'expires_in': expires_in}

    res = make_response(redirect('http://localhost/about', code=302))

    # I'd rather send token_info to `localStorage` at my client, instead of setting cookies
    #res.set_cookie('access_token', access_token)
    #res.set_cookie('refresh_token', refresh_token)
    #res.set_cookie('token_type', token_type)
    #res.set_cookie('expires_in', str(expires_in))

    return res

Есть ли способ отправить 'token_info' выше с jsonify() (или еще) клиенту через make_response() до происходит перенаправление?

1 Ответ

2 голосов
/ 31 марта 2020

Пожалуйста, прочитайте примечания, если вы беспокоитесь о потоке OAuth!

Согласно HTTP 302 Redirect - нужен ли текст сообщения? , вы может вернуть тело в 302 Redirect. Действительно, RFC2616 не запрещает отправлять тело ответа.

Что ж, я не эксперт по Flask, но это должно сработать. Возвращает JSON в теле ответа 302 Redirect. Обратите внимание, что вы также должны установить правильный заголовок Content-Type (в моем примере это не сделано).

import json
from flask import Flask, redirect, Response
app = Flask(__name__)

def jsonResponseFactory(data):
    '''Return a callable in top of Response'''
    def callable(response=None, *args, **kwargs):
        '''Return a response with JSON data from factory context'''
        return Response(json.dumps(data), *args, **kwargs)
    return callable

@app.route('/')
def hello_world():
    token_info = {
        'access_token': '...',
        'refresh_token': '...',
        'token_type': '...',
        'expires_in': '...' 
    }

    return redirect(
        'http://localhost/about',
        302,
        jsonResponseFactory(token_info)
    )

Кстати, если вашему клиенту нужно прочитать токен, он не должен автоматически следовать редирект! Кроме того, я не знаю, является ли 302 Redirect лучшим ответом для вашей конечной точки обратного вызова OAuth. Но все это зависит от контекста.

Редактировать: Вот некоторые заметки после комментариев к комментариям.

  1. Вы не должны хранить токены в localStorage. Хорошее объяснение с сайта Auth0 . Кроме того, браузеры (начиная с Safari) теперь будут сбрасывать localStorage через 7 дней без взаимодействия с пользователем
  2. Снова из Auth0 (и я полностью согласен) токен должен быть обработан на стороне сервера.
  3. Я оставлю свой ответ таким, какой он есть (даже если область действия не идеальна), потому что он фактически отвечает на ваш вопрос, связанный с HTTP.
...