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

保罗·高德

我正在尝试使用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检查之后才调用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

但这只是造成了相同的行为。

我从此先前的SO中看到,建议库作者执行此操作的方法是仅创建两个单独的Flask-HTTPAuth对象。我可以做到的,没问题。但是很明显,我关于装饰器工作方式的思维模型失败了,所以我想独立于获得我想要的功能来解决这个问题。

米格尔

有时,在不知道装饰器的作用的情况下,很难确定装饰器的正确使用顺序,但是不幸的是,错误的顺序将使应用程序的行为不正确。

对于在视图功能“之前”运行的装饰器,在这种情况下,通常必须按所需的顺序放置装饰器。因此,我认为您的代码将达到您在使用Flask-HTTPAuthlogin_required之前的期望must_be_admin

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

通过 DI 在 IHostedService 中利用用户上下文

如何通过DRM创建OpenGL上下文(Linux)

使用React上下文维护用户状态

kubectl配置使用上下文删除eks用户

使用React上下文的用户身份验证

如何使用上下文为ServiceAccount创建角色

无法使用外部QOpenGLWidget创建的上下文?

使用PyQt5创建上下文菜单

使用GLUT / FreeGLUT创建核心上下文?

使用 JQuery 获取创建的画布的上下文

如何通过上下文类内部方法中创建的onClick函数传递React上下文的状态?

流星:为什么我通过将function(){}切换为()=> {}来丢失数据上下文?

上下文创建失败

为什么在使用反应上下文时会出现丢失的 <Text> 错误?

如果使用左键单击事件显示 WPF ContextMenu 会丢失数据上下文

Grails Web Flow插件-在子流中使用时流上下文丢失

使用正确的上下文

Linux上的共享库:为什么动态链接器在用户上下文中运行?

使用来自 Activity 的上下文从 Adapter 类中的 Viewholder 创建对象 - 没有为“上下文”传递值

lib OSMesa屏幕外上下文创建在C ++中失败,但仅在静态链接时

通过提供安全上下文,以root:artifact身份创建的卷装入

无法通过brew安装带有GLFW的OpenGL 3.3上下文macOS创建窗口

通过枚举值列表创建可检查的上下文菜单的通用方法

如何通过EGL创建OpenGL 3.3或4.x上下文

如何通过wpf中页面的上下文菜单创建子窗口?

如何使用用户主体上下文从 Active Directory 中检索电话号码

设置数据上下文时如何使用用户控件依赖项属性?

如何使用请求中从Twitter OAuth 1.0a获得的“用户上下文访问令牌”?

Dropwizard:使用dhatim / dropwizard-sentry时如何设置Sentry用户上下文[已修复]