通过Flask中的装饰器进行身份验证 [英] Authentication via decorators in Flask
问题描述
我有以下有效的代码.它验证给定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'))
上面的代码有效,我想用它做一个装饰器.所以我写了以下内容.但是,它不起作用,因为
的值用户=无
代码段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'
装饰器的顺序很重要.如果代码的结构与问题相同,则admin_routes
装饰basic
并返回一个函数(funcA
).然后,该函数funcA
由authenticate_admin
装饰,该函数返回funcB
.因此,实际上分配给路由的回调的函数是给admin_routes
的函数,它是basic
,而不是装饰版的basic(funcA
或funcB
).因此,您的funcB
不会被调用,因此不会执行您的身份验证逻辑
将订单更改为
@admin_routes.route('/xxxx')
@authenticate_admin
def basic():
...
此处authenticate_admin
返回修饰的函数funcA
,然后由admin_routes
修饰.因此,分配为回调的函数是funcA
而不是basic
.因此,当您转到/xxxx
,funcA
并执行身份验证逻辑时.
错误似乎是当您未登录时导航至/xxxx
时,它尝试使用user=None
尝试render_template
,并且很可能您的模板使用的是user.nickname
,即AttributeError
.>
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'
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
.
这篇关于通过Flask中的装饰器进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!