Flask - 在使用 make_request 重定向之前将 JSON 数据发送到客户端

Posted

技术标签:

【中文标题】Flask - 在使用 make_request 重定向之前将 JSON 数据发送到客户端【英文标题】:Flask - send JSON data to client before redirecting with make_request 【发布时间】:2020-07-11 05:35:50 【问题描述】:

我有这个带有重定向的回调 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

有没有办法在重定向发生之前通过make_response() 将上面带有jsonify()(或其他)的“token_info”发送给客户端?

【问题讨论】:

res = make_response('<script>document.location.href="/about"</script>');... 我猜也许 想给出正式而完整的答案吗?谢谢! @JoranBeasley 你的脚本重定向,我如何传递 json? 【参考方案1】:

如果您担心 OAuth 流程,请阅读脚注!

根据HTTP 302 Redirect - is a message-body needed?,您可以在302 Redirect 中返回一个正文。事实上RFC2616 并不禁止发送响应正文。

好吧,我不是 Flask 专家,但这应该可以胜任。它在 302 Redirect 响应的正文中返回 JSON。请注意,您还应该设置正确的 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 回调端点的最佳答案。但这一切都取决于上下文。

编辑: 以下是cmets反馈后的一些注意事项。

    您不应将令牌存储在localStorage 中。 Auth0 website 有一个很好的解释。此外,浏览器(从 Safari 开始)will now drop localStorage after 7 days without user interaction 同样来自Auth0(我完全同意)令牌应该在服务器端处理。 我会照原样回答(即使范围不理想),因为它实际上是对您的 HTTP 相关问题的回答。

【讨论】:

谢谢!它不应该遵循重定向,而是在重定向之前发送正文。我只需要发送正文,以便将数据存储在localStorage() 中。有意义吗? 实际上正文是在重定向完成之前发送的。但是,如果我很了解您的用例,这是“授权代码授予”的回调。如果是这样,这里有很多事情: - IMO 你不应该将 access_token 或 refresh_token 存储在本地存储中(多种原因,这里有一个很好的指南:auth0.com/docs/tokens/guides/…) - IMO(再次)你应该处理你的访问/刷新令牌在您的后端(这里又是一个很好的指南:auth0.com/docs/tokens/guides/…) 我将编辑我的答案,为您提供有关您评论的更多详细信息... ;-) 我知道,我有一个悬而未决的问题,关于我对令牌处理的怀疑。 [***.com/q/60859658/3451339]。有人说,将状态保留在后端是不可取的,因为之后会进行扩展,以及过时的做法,而且至少我的秘密凭据没有暴露。去寻找答案! 我编辑了这个。 :-) 我会尽快看看另一个问题!我希望这个已经可以帮助需要在302 Redirect 中回复正文的 Flask 用户,即使这并不是你的“最终目的”。

以上是关于Flask - 在使用 make_request 重定向之前将 JSON 数据发送到客户端的主要内容,如果未能解决你的问题,请参考以下文章

使用flask和flask-socketio配置nginx、uwsgi

Flask插件系列之flask_celery

python之celery在flask中使用

结合manage.py,在flask项目中使用 flask-socketio

Flask

是否可以将 Flask RestX 与 Flask 2.0+ 异步等待一起使用?