我有以下代码可行。它为给定URL的管理员用户进行身份验证。如果用户不是Admin,则返回401。
摘录1:
__author__ = 'xxxx'
from flask import render_template, url_for
from flask import Blueprint, redirect, request, session, abort
from google.appengine.api import users
admin_routes = Blueprint('admin_routes', __name__)
@admin_routes.route('/xxxx')
def basic():
user = users.get_current_user()
if user:
if not users.is_current_user_admin():
return abort(401)
else:
return render_template('xxx/xxxx.html', user=user,
logout=users.create_logout_url('/'))
else:
return redirect(users.create_login_url('/xxxx'))
上面的代码有效,我想用它做一个装饰器。所以我写了以下内容。但它不起作用,作为
的值user =无
摘录2:
from google.appengine.api import users
from flask import abort, redirect
def authenticate_admin(func):
def authenticate_and_call(*args, **kwargs):
user = users.get_current_user()
if user is None:
print("Redirecting user to login page")
return redirect(users.create_login_url('xxxxx/xxxx'), 401)
else:
if not users.is_current_user_admin():
return abort, 401
return func(*args, **kwargs)
return authenticate_and_call()
我如何编写装饰器,以便它完成Snippet 1所做的工作。最终结果应该是这样的。
__author__ = 'xxxxxx'
from flask import render_template, url_for
from flask import Blueprint, redirect, request, session, abort
from google.appengine.api import users
admin_routes = Blueprint('admin_routes', __name__)
@authenticate_admin
@admin_routes.route('/xxxx')
def basic():
return render_template('xxx/xxxx.html', user=user,
logout=users.create_logout_url('/'))
我获得上述代码的例外是
UndefinedError: 'None' has no attribute 'nickname'
答案 0 :(得分:4)
装饰者的顺序很重要。如果代码的结构与问题相同,则admin_routes
会修饰basic
并返回一个函数(funcA
)。该函数funcA
随后由authenticate_admin
修饰,返回funcB
。因此,实际被指定为路径回调的函数是admin_routes
赋予的函数basic
而不是基本(funcA
或funcB
的修饰版本) 。因此,永远不会调用funcB
,因此不会执行您的身份验证逻辑
将订单更改为
时@admin_routes.route('/xxxx')
@authenticate_admin
def basic():
...
此处authenticate_admin
返回已修饰的函数funcA
,然后由admin_routes
修饰。因此,分配为回调的函数为funcA
而不是basic
。因此,当您转到/xxxx
,funcA
并执行您的身份验证逻辑时。
错误似乎是当您未登录时导航到/xxxx
,它会尝试使用render_template
user=None
,并且您的模板很可能使用user.nickname
是AttributeError
。
答案 1 :(得分:1)
我认为您需要将authenticate_admin
的返回值作为authenticate_and_call
函数,而不是其调用authenticate_and_call()
:
return authenticate_and_call