【问题标题】:What is the best practice for changing headers in a Flask request?在 Flask 请求中更改标头的最佳做法是什么?
【发布时间】:2020-06-19 07:28:57
【问题描述】:

我有一个 Flask 应用程序,它使用自定义装饰器来验证在 HTTP 标头属性中传递的 AWS Cognito 登录令牌。该过程包括刷新令牌(这超出了本问题的范围)。获得刷新的令牌后,我想更新标头属性以包含刷新的令牌并退出。由于 Flask/Werkzeug request.headers 属性是不可变的,我无法通过正常方式对其进行更新。

如何在这个装饰器的上下文中更新标题?有没有我没有想到的更好的方法?

以下是一些演示该问题的示例代码:

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        token = request.headers.get('X-MyApp-Auth')
        if not token:
            return redirect(url_for('login', next=request.url))
        # Test for expired token (pseudocode)
        if expired(token):
            # Refresh the token (pseudocode)
            new_token = refresh(refresh_token)
            # This is the part where the immutability gets me stuck
            request.headers.set('X-MyApp-Auth', new_token)
        return f(*args, **kwargs)
    return decorated_function

【问题讨论】:

  • 请检查此link 是否可以回答您的问题?

标签: http flask http-headers werkzeug


【解决方案1】:

我遇到了同样的问题 - 我有一个装饰器,它执行清理、身份验证并提供整个应用程序使用的授权信息。

带有 request.headers 的两个设计点使它们难以使用。 a) 数据不可变,b) 键不区分大小写。

我解决此问题的一种方法是将请求标头复制到另一个数据结构中,该结构具有真正可接受的内容,而不是黑客提供的任何内容。

from requests.structures import CaseInsensitiveDict
copy = CaseInsensitiveDict()
for k, v in request.headers:
    copy[k] = v

这可以扩展到白名单过滤必要的标题,根据https://owasp.org/www-project-top-ten/2017/A1_2017-Injection 清理值,并使用自定义私人信息修改参数块。

此方法不会更新 request.headers 对象。你应该开发一种模式,让你的应用程序的参数块用户是可信的,而烧瓶提供的块是不可信的。

【讨论】:

    【解决方案2】:

    request.headers 是您的服务器从客户端应用程序收到的 HTTP 标头, 因此,您无法更新这些是有道理的。 您可能正在寻找可以在此线程之后设置的响应标头: How do I set response headers in Flask?

    【讨论】:

      【解决方案3】:

      此示例将 Flask 应用程序包装在自定义 WSGI 中间件中,该中间件在 Flask 请求处理之前修改 WSGI 环境:

      from flask import Flask, request, jsonify
      
      
      class InterceptRequestMiddleware:
          def __init__(self, wsgi_app):
              self.wsgi_app = wsgi_app
      
          def __call__(self, environ, start_response):
              environ['HTTP_USER_AGENT'] = 'foobar'
              return self.wsgi_app(environ, start_response)
      
      
      app = Flask(__name__)
      app.wsgi_app = InterceptRequestMiddleware(app.wsgi_app)
      
      
      @app.route('/')
      def index():
          return jsonify({'headers': {k: v for k, v in request.headers}})
      
      
      if __name__ == '__main__':
          app.run(debug=True)
      

      链接:

      【讨论】:

        猜你喜欢
        • 2015-04-06
        • 1970-01-01
        • 2017-10-01
        • 1970-01-01
        • 2021-11-16
        • 2012-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多