【问题标题】:Authentication via decorators in Flask通过 Flask 中的装饰器进行身份验证
【发布时间】:2015-10-23 18:17:21
【问题描述】:

我有以下有效的代码。它对给定 url 的管理员用户进行身份验证。如果用户不是管理员,则返回 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'))

上面的代码有效,我想用它做一个装饰器。所以我写了以下内容。但是它不起作用,因为

的值

用户 = 无

片段 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'

【问题讨论】:

  • 你可以尝试改变装饰器的顺序吗?你想用@admin_routes装饰的函数是已经被authenticate_admin装饰的函数吧?感觉就像@admin_routes 将路由分配给函数basic,当您路由到/xxxx 时,它使用函数basic 进行路由,而您的render_template 使用user.nickname,其中您的userNone
  • @hgwells。是的,更改顺序已经奏效。我想知道为什么?

标签: python google-app-engine flask python-decorators


【解决方案1】:

装饰器的顺序很重要。如果代码的结构与问题中的一样,admin_routes 装饰 basic 并返回一个函数 (funcA)。该函数funcA 然后由返回funcBauthenticate_admin 修饰。因此,实际分配为路由回调的函数是分配给admin_routes 的函数,即basic,而不是基本的修饰版本(funcAfuncB)。因此,您的 funcB 永远不会被调用,因此您的身份验证逻辑不会被执行

当您将订单更改为

@admin_routes.route('/xxxx')
@authenticate_admin
def basic():
    ...

这里authenticate_admin 返回修饰函数funcA,然后由admin_routes 修饰。所以分配为回调的函数是funcA 而不是basic。所以当你去/xxxxfuncA,你的认证逻辑就会被执行。

错误似乎是当您未登录时导航到/xxxx,它尝试使用user=None 访问render_template,并且很可能您的模板使用user.nickname,这是一个AttributeError

【讨论】:

    【解决方案2】:

    我认为您需要 authenticate_admin 的返回值是 authenticate_and_call 函数,而不是它的调用 authenticate_and_call()

        return authenticate_and_call
    

    【讨论】:

    • 试过了我仍然收到异常 UndefinedError: 'None' has no attribute 'nickname'
    • 我不熟悉烧瓶,所以我不确定这个:我的装饰器也不会在 redirect 和 @987654327 的等价物前面使用 return @调用...
    猜你喜欢
    • 2019-07-02
    • 2020-08-15
    • 2014-08-25
    • 2013-10-31
    • 2012-06-13
    • 2010-11-11
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多