5

ねじれた 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 が生成されます

4

3 に答える 3