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

时间:2015-07-31 23:52:56

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

我有以下代码可行。它为给定URL的管理员用户进行身份验证。如果用户不是Admin,则返回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 =无

摘录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'

2 个答案:

答案 0 :(得分:4)

装饰者的顺序很重要。如果代码的结构与问题相同,则admin_routes会修饰basic并返回一个函数(funcA)。该函数funcA随后由authenticate_admin修饰,返回funcB。因此,实际被指定为路径回调的函数是admin_routes赋予的函数basic而不是基本(funcAfuncB的修饰版本) 。因此,永远不会调用funcB,因此不会执行您的身份验证逻辑

将订单更改为

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

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

错误似乎是当您未登录时导航到/xxxx,它会尝试使用render_template user=None,并且您的模板很可能使用user.nicknameAttributeError

答案 1 :(得分:1)

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

    return authenticate_and_call
相关问题