用FlaskHTTPAuth创建特权用户,方法是通过链接decorators来丢失上下文?

2024-10-06 10:31:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我尝试使用flaskhttpauth创建一个具有basic auth的两层身份验证系统。我的应用程序有两个路由,一个位于/的基本路由可供任何登录的用户访问,另一个位于/admin的管理路由只对以管理员身份登录的用户访问。在

所以我决定通过链接decorators来实现这一点,代码的相关部分如下(其中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()返回的是一个空字符串。因此,我的猜测是,由于某些原因,没有应用内部装饰器,因此缺少登录提示。在

有人知道这里会发生什么吗?在

我的第一个假设是这是一个很容易的bug,因为管理装饰器上的内部函数直到is_admin检查之后才被调用。因此,我尝试在检查之前修复我调用函数的问题,从而推测auth.username()可用,如下所示:

^{pr2}$

但这也导致了同样的行为。在

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


Tags: 用户auth路由returnadmin管理员defusername
1条回答
网友
1楼 · 发布于 2024-10-06 10:31:32

应用decorator的正确顺序有时很难在不知道decorator做什么的情况下确定,但不幸的是,错误的顺序会使应用程序行为不正确。在

对于在视图函数运行之前执行某项操作的decorator,如本例中所示,通常必须将decorator按您希望它们执行的顺序排列。因此,我认为当您在must_be_admin之前使用Flask HTTPAuth的login_required时,您的代码将实现您所期望的效果:

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

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

相关问题 更多 >