我正在使用下面的装饰器来验证我的应用程序中的端点。
from google.appengine.api import users
from flask import redirect, render_template, request
from google.appengine.ext import ndb
def authenticate_admin(func):
def authenticate_and_call(*args, **kwargs):
user = users.get_current_user()
if user is None:
return redirect(users.create_login_url(request.url))
else:
email = user.email()
register_user_if_required(email, user)
if not users.is_current_user_admin():
return redirect_to_unauthorized(email)
return func(*args, **kwargs)
def redirect_to_unauthorized(email):
return render_template('xxxx/vvvv.html',
email=email,
users=users)
return authenticate_and_call
def register_user_if_required(email, user):
我有以下端点,只允许管理员访问它。
@admin_routes.route('/xxxx')
@authenticate_admin
def xxxxx():
return render_template('xxxx/xxxxx.html',
user=user,
logout=users.create_logout_url('/'))
它的工作原理是只有管理员才能访问上述端点。但是,当我尝试添加具有相同注释但具有不同花哨网址的新端点时,我收到错误。这是端点的代码。
@admin_routes.route('/xxxx/bbbbbb')
@authenticate_admin
def abc():
.....
return render_template('xxxx/xxxx/zzzzz.html',
user=user,
breadcrumb=breadcrumb)
这是我运行应用程序时遇到的错误。
Traceback (most recent call last):
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler
handler, path, err = LoadObject(self._handler)
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject
obj = __import__(path[0])
File "/Users/vinay/App-Engine/xxxxx/main.py", line 61, in <module>
app.register_blueprint(admin_routes)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/app.py", line 62, in wrapper_func
return f(self, *args, **kwargs)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/app.py", line 889, in register_blueprint
blueprint.register(self, options, first_registration)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/blueprints.py", line 153, in register
deferred(state)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/blueprints.py", line 172, in <lambda>
s.add_url_rule(rule, endpoint, view_func, **options))
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/blueprints.py", line 76, in add_url_rule
view_func, defaults=defaults, **options)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/app.py", line 62, in wrapper_func
return f(self, *args, **kwargs)
File "/Users/vinay/App-Engine/xxxxx/server/lib/flask/app.py", line 984, in add_url_rule
'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint function: admin_routes.authenticate_and_call
Traceback (most recent call last):
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ereporter/ereporter.py", line 240, in emit
record.exc_info)
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/datastore.py", line 2520, in RunInTransactionCustomRetries
return RunInTransactionOptions(options, function, *args, **kwargs)
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/datastore.py", line 2630, in RunInTransactionOptions
ok, result = _DoOneTry(function, args, kwargs)
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/datastore.py", line 2650, in _DoOneTry
result = function(*args, **kwargs)
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ereporter/ereporter.py", line 270, in __EmitTx
handler=self.__RelativePath(os.environ['PATH_TRANSLATED']))
File "/Users/vinay/Desktop/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/request_environment.py", line 113, in __getitem__
return self._request.environ[key]
KeyError: 'PATH_TRANSLATED'
Logged from file wsgi.py, line 263
INFO 2015-08-09 03:19:14,731 module.py:812] default: "GET / HTTP/1.1" 500 -
答案 0 :(得分:4)
您需要确保您的装饰器包装器与包装的视图功能具有相同的名称,否则您的所有视图看起来都是相同的端点(authenticate_and_call
)。
您可以使用@functool.wraps()
utility:
from functools import wraps
def authenticate_admin(func):
@wraps(func)
def authenticate_and_call(*args, **kwargs):
user = users.get_current_user()
if user is None:
return redirect(users.create_login_url(request.url))
else:
email = user.email()
register_user_if_required(email, user)
if not users.is_current_user_admin():
return redirect_to_unauthorized(email)
return func(*args, **kwargs)
def redirect_to_unauthorized(email):
return render_template('Admin/UnauthorizedAdmin.html',
email=email,
users=users)
return authenticate_and_call
这可确保将函数名称等元数据从func
复制到authenticate_and_call
包装器。从那里开始@Flask.route()
可以选取该名称作为端点名称。