在Flask中更改/替换不可变请求对象
我现在正在为一个非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_type
和client_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)