ねじれた Web API を実装しました。
認証を処理するために、いくつかのルートをラップするデコレーターを使用しました。
@requires_auth(roles=[Roles.Admin])
def get_secret_stuff(request):
return 42
requires_auth
ラッパーは次のように実装されます。
def requires_auth(roles):
def wrap(f):
def wrapped_f(request, *args, **kwargs):
# If the user is authenticated then...
return f(request, *args, **kwargs)
return wrapped_f
return wrap
問題は、このデコレーターに複数のルートがある場合、それらのいずれかを呼び出すと、装飾される最新のルートが呼び出されることです。
これは明らかに私が望んでいたことではなく、デコレーターがどのように機能するべきかについての私の理解に反しています。コードにいくつかの印刷ステートメントを追加して、それを理解しようとしました。
def requires_auth(roles):
def wrap(f):
print(f) # This shows that the decorator is being called correctly once per each
# route that is decorated
def wrapped_f(request, *args, **kwargs):
# If the user is authenticated then...
return f(request, *args, **kwargs)
return wrapped_f
return wrap
重要な場合は、これらのルートの一部にツイストの inlineCallbacks を使用し、@app.route(url, methods)
これらすべてのルートにツイスト Web のデコレータを使用しています。
読んでくれてありがとう :)
編集:これは悪い考えだと言われたので、コンストラクターへのデフォルトの引数を削除しました:)
編集:これは問題を説明する最小限の例です:
from klein import Klein
import json
app = Klein()
def requires_auth(roles):
def wrap(f):
print('inside the first clojure with f=%s' % str(f))
def wrapped_f(request, *args, **kwargs):
print('inside the second closure with f=%s' % str(f))
return f(request, *args, **kwargs)
return wrapped_f
return wrap
@app.route('/thing_a')
@requires_auth(roles=['user'])
def get_a(request):
return json.dumps({'thing A': 'hello'})
@app.route('/thing_b')
@requires_auth(roles=['admin'])
def get_b(request):
return json.dumps({'thing B': 'goodbye'})
app.run('0.0.0.0', 8080)
ルート '/thing_a' に移動すると、route_b からの json が生成されます