通过 Flask 中的装饰器进行身份验证

Authentication via decorators in Flask

我有以下有效的代码。它为给定的 url 验证管理员用户。如果用户不是管理员,那么它 returns 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'))

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

的值

user = None

片段 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()

我将如何编写装饰器以实现代码段 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'

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

    return authenticate_and_call

装饰器的顺序很重要。如果代码的结构与问题中的相同,则 admin_routes 装饰 basic 和 returns 一个函数(funcA)。该函数 funcA 然后由 authenticate_admin 修饰,其中 returns funcB。所以实际分配给路由回调的函数是给 admin_routes 的函数,它是 basic 而不是 basic 的装饰版本(funcA,或 funcB) .所以你的 funcB 永远不会被调用,因此你的身份验证逻辑不会被执行

当您将订单更改为

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

这里 authenticate_admin returns 修饰函数 funcA 然后由 admin_routes 修饰。因此,分配为回调的函数是 funcA 而不是 basic。因此,当您转到 /xxxxfuncA 并执行您的身份验证逻辑时。

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