Authentication via decorators in Flask

别来无恙 提交于 2019-12-12 10:24:15

问题


I have the following code which works. It authenticates admin users for the given url. If the users is not Admin then it returns a 401.

Snippet 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:

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. 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'

回答1:


The order of decorators matter. If the code is structured as in the question, admin_routes decorates basic and returns a function (funcA). That function, funcA, is then decorated by authenticate_admin which returns 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). So your funcB is never called and hence your authentication logic is not executed

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. So the function assigned as a callback is funcA not basic. So when you go to /xxxx, funcA and your authentication logic is executed.

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.




回答2:


I think you need the return value of authenticate_admin to be the authenticate_and_call function, not its invocation authenticate_and_call():

    return authenticate_and_call


来源:https://stackoverflow.com/questions/31756830/authentication-via-decorators-in-flask

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!