简体   繁体   English

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

[英]Authentication via decorators in Flask

I have the following code which works. 我有以下有效的代码。 It authenticates admin users for the given url. 它验证给定URL的管理员用户。 If the users is not Admin then it returns a 401. 如果用户不是管理员,则返回401。

Snippet 1: 片段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'))

The above code works and I wanted to make a decorator out of it. 上面的代码有效,我想用它做一个装饰器。 So I wrote the following. 所以我写了以下内容。 However it does not work, as the value of 但是,它不起作用,因为

user = None 用户=无

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

How would I write the decorator so it does what the Snippet 1 does. 我将如何编写装饰器,使其完成代码段1的工作。 End result should be something like so. 最终结果应该是这样的。

__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('/'))

The exception i get for the above code is 我上面的代码得到的异常是

UndefinedError: 'None' has no attribute 'nickname'

The order of decorators matter. 装饰者的顺序很重要。 If the code is structured as in the question, admin_routes decorates basic and returns a function ( funcA ). 如果代码按照问题的结构进行构造,则admin_routes装饰basic并返回一个函数( funcA )。 That function, funcA , is then decorated by authenticate_admin which returns funcB . 然后,该函数funcAauthenticate_admin装饰,该函数返回funcB So the function that actually is assigned as callback for the route is the function given to admin_routes which is basic and not the decorated version of basic ( funcA , or funcB ). 因此,实际上分配给路由的回调的函数是给admin_routes的函数,它是basic函数,而不是basic的修饰版本( funcAfuncB )。 So your funcB is never called and hence your authentication logic is not executed 因此,您的funcB不会被调用,因此不会执行身份验证逻辑

When you change the order to 当您将订单更改为

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

Here authenticate_admin returns the decorated function funcA which is then decorated by admin_routes . 这里authenticate_admin返回修饰的函数funcA ,然后由admin_routes修饰。 So the function assigned as a callback is funcA not basic . 因此,分配为回调的funcA不是funcA basic So when you go to /xxxx , funcA and your authentication logic is executed. 因此,当您转到/xxxxfuncA就会执行身份验证逻辑。

The error seems to be when you navigate to /xxxx when you are not logged in, it tries to render_template with user=None and most likely your template uses user.nickname which is an AttributeError . 错误似乎是当您未登录时导航到/xxxx时,它尝试使用user=None user.nickname render_template ,并且很可能您的模板使用user.nickname ,这是AttributeError

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

    return authenticate_and_call

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM