通过链接装饰器来创建使用Flask-HTTPAuth的特权用户 - 丢失上下文?

问题描述 投票:2回答:1

我正在尝试使用Flask-HTTPAuth创建一个带有基本身份验证的双层身份验证系统。我的应用程序有两条路由,/的基本路由可供任何登录用户访问,/admin的管理路由只能访问(如您所料)以管理员身份登录的用户。

所以我决定通过链接装饰器来实现它,代码的相关部分如下所示(其中dbops只是一个处理与数据库对话的命名空间):

@auth.verify_password
def verify_pw(lastname, password):
    ln = lastname.lower()
    if ln in dbops.list_users():
        hashed_pw = dbops.find_hashed_password(ln)
        return bcrypt.checkpw(password.encode('utf8'), hashed_pw.encode('utf8'))
    return False

def must_be_admin(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        if dbops.is_admin(auth.username()):
            return f(*args, **kwargs)
        return "Not authorized."
    return wrapper

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

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

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

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

有谁知道这里会发生什么?

我的第一个假设是,这是一个简单的错误,因为管理装饰器的内部函数直到is_admin检查后才被调用。因此,我试图在检查之前修复我调用函数---因此可能使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

但这只是造成同样的行为。

我从this prior SO看到,从库作者那里推荐的方法是创建两个单独的Flask-HTTPAuth对象。哪个我能做,没问题。但很明显我关于装饰器如何工作的心理模型是失败的,所以我想解决这个问题,而不是获得我想要的功能......

python flask basic-authentication python-decorators flask-httpauth
1个回答
2
投票

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

对于在视图函数运行之前执行某些操作的装饰器,就像在这种情况下一样,您通常必须按照您希望它们执行的顺序放置装饰器。所以我认为当你在login_required之前使用Flask-HTTPAuth的must_be_admin时,你的代码会做你期望的:

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

通过这种方式,将首先检查凭据,如果丢失或无效,login_required将向浏览器返回401错误,这将使登录提示出现。只有在确定凭据有效后,您才需要评估管理员装饰器。

© www.soinside.com 2019 - 2024. All rights reserved.