在Flask中更改/替换不可变请求对象

3 投票
2 回答
4534 浏览
提问于 2025-04-18 07:56

我现在正在为一个非REST API做Oauthlib-Flask的实现。不过我遇到了两个情况,想要修改或添加flask请求对象中的某个值。因为这个对象是不可变的,所以操作起来并不简单。我试着按照改变werkzeug请求对象的值里的建议去做,创建了一个副本。但由于@oauth.authorize_handler使用的是给定的请求对象,我必须替换它,这样就会出现UnboundLocalError: local variable 'request' referenced before assignment的错误。以下是我的示例代码(这是隐式授权的一部分):

@app.route('/oauth/authorize', methods=['GET', 'POST'])
@login
@oauth.authorize_handler
def authorize(*args, **kwargs):
    if request.method == 'GET':
        client_id = kwargs.get('client_id')
        client = Client.query.filter_by(client_id=client_id).first()
        kwargs['client'] = client
        return render_template('authorize.html', **kwargs)

    r = make_duplicate_request(request)
    #Change/add values of r
    request = r
    return True

我是不是做错了什么,或者有没有其他方法可以改变请求对象呢?

谢谢你的帮助!

更新: 上面的代码描述了我想把信息传递给tokensetter函数的情况。这可以通过全局变量来实现,但我想避免这样做。

在我的注册流程中,客户端向API发送了这样的请求:

params_signup = {
    "schemas":["urn:scim:schemas:core:2.0:User"],
    "expireIn":3600,
    "username":"test@web.de",
    "password":"123",
    "access_token":"",
    "externalId":"tmeinhardt",
    "grant_type":"password",
    "client_id":"1",           
    "params":{
        "age":"20-30",
        "gender":"m",
        }
   }

我只需要grant_typeclient_id这部分信息用于tokenhandler,并想手动添加到请求对象中。但因为这个对象是不可变的……

2 个回答

0

你可以创建一个新的请求,并把头信息放进一个新的字典里,这个字典是一个HttpRequest的对象(比如说,Authlib的HttpRequest)。

from flask import request as _req
from authlib.oauth2.rfc6749 import HttpRequest

request = HttpRequest(
    _req.method, _req.full_path, _req.data, {**_req.headers, **auth}
)
request.req = _req

然后你就可以使用这个新的请求,而不是Flask的请求了。

2

写这段话是为了帮助那些正在尝试实现OAuth流程的人。

不要使用装饰器,改用中间件

我认为你应该在中间件中处理这个问题。在中间件里,你可以设置call函数的第二个参数中的授权属性,这个参数包含了你在init函数中传入的当前wsgi应用的环境变量。看看下面的代码:

def __init__(self, app):
    self.app = app

def __call__(self, environ, start_response):
    cookie = Request(environ).cookies.get('access_token')
    if cookie is not None:
        environ['HTTP_AUTHORIZATION']='Bearer '+cookie
    return self.app(environ, start_response)

撰写回答