Python 通过链接decorators使用Flask HTTPAuth创建特权用户——丢失上下文?

Python 通过链接decorators使用Flask HTTPAuth创建特权用户——丢失上下文?,python,flask,basic-authentication,python-decorators,flask-httpauth,Python,Flask,Basic Authentication,Python Decorators,Flask Httpauth,我正在尝试使用Flask HTTPAuth创建一个具有基本身份验证的两层身份验证系统。我的应用程序有两个路由,一个位于/的基本路由可供任何登录用户访问,另一个位于/admin的管理员路由仅可供作为管理员登录的用户访问 因此,我决定通过链接decorators来实现这一点,代码的相关部分如下(其中dbops只是一个处理与数据库对话的名称空间): 只要试图以管理员用户身份登录的任何人首先访问/路径,这项功能就可以正常工作:它会提示输入用户名和密码,然后管理员用户可以转到/admin并执行登录的管理员

我正在尝试使用Flask HTTPAuth创建一个具有基本身份验证的两层身份验证系统。我的应用程序有两个路由,一个位于
/
的基本路由可供任何登录用户访问,另一个位于
/admin
的管理员路由仅可供作为管理员登录的用户访问

因此,我决定通过链接decorators来实现这一点,代码的相关部分如下(其中dbops只是一个处理与数据库对话的名称空间):

只要试图以管理员用户身份登录的任何人首先访问
/
路径,这项功能就可以正常工作:它会提示输入用户名和密码,然后管理员用户可以转到
/admin
并执行登录的管理员任务

但是,如果管理员用户首次访问
/admin
,则不会给出登录提示。它只是抛出,在调试器中四处搜索之后,我确定
auth.username()
返回的是一个空字符串。因此,我猜想由于某种原因,没有应用内部装饰程序,因此缺少登录提示

有人知道这里发生了什么吗

我的第一个假设是这是一个简单的bug,因为在
is_admin
检查之后,才调用admin decorator上的内部函数。因此,我尝试在检查之前,通过调用函数来修复此问题,并假定
auth.username()
可用,如下所示:

def must_be_admin(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        dummy_to_get_username = f(*args, **kwargs)
        if dbops.is_admin(auth.username()):
            return dummy_to_get_username
        return "Not authorized."
    return wrapper
但这只是导致了同样的行为


我从中了解到,库作者推荐的方法是只创建两个单独的Flask HTTPAuth对象。我能做到,没问题。但很明显,我关于装饰器如何工作的思维模式失败了,所以我想独立于获得我想要的功能来解决这个问题…

在不知道装饰器做什么的情况下,应用装饰器的正确顺序有时很难弄清楚,但不幸的是,错误的顺序会使应用程序行为不正确

对于“在”视图函数运行之前执行某些操作的装饰器,如本例中所示,您通常必须按照希望它们执行的顺序放置装饰器。因此,我认为,在您的
必须是管理员之前,当您使用Flask HTTPAuth的
登录时,您的代码将实现您所期望的:

@core.route("/admin")
@auth.login_required
@must_be_admin
def admin():
    return render_template("admin.html")

这样,将首先检查凭据,如果缺少或无效,则
login\u required
将向浏览器返回401错误,从而显示登录提示。只有在确定凭据有效后,您才需要评估管理员装饰程序。

非常感谢!你在这里如此积极地回答所有的问题,真是太好了。
@core.route("/admin")
@auth.login_required
@must_be_admin
def admin():
    return render_template("admin.html")