I've figured out how to make Flask-Login authenticate a user based on an LDAP lookup. Now I'd like to add some authorization to the mix - that is, only allow access to certain endpoints if a user has both logged in and belongs to the right groups.
I'm not sure if this is the right way to do it, but I thought I could just add a decoration to an endpoint:
@app.route('/top_secret')
@authorize
@login_required
def top_secret():
return render_template("top_secret.html")
and (for now) make a completely pass-through decorator:
def authorize(func):
def newfunc(*args, **kwargs):
return func(*args, **kwargs)
return newfunc
But running this gives the error:
werkzeug.routing.BuildError: Could not build url for endpoint 'top_secret'.
while running it without the @authorize decorator works fine.
So I'm not sure where I went wrong. Can I not decorate endpoints in this way? And if not, where should the authorization step take place? (it would have to take place after @login_required has finished what it needs to do)
Ah, yeah, super simple!
from functools import wraps
def authorize(func):
@wraps(func)
def newfunc(*args, **kwargs):
return func(*args, **kwargs)
return newfunc
To understand why you need wraps
, you can do this:
print(top_secret)
Once with wraps, and once without. With wraps, you'll see something like this:
<function top_secret at 0x7ff165150840>
Without it, you'll see:
<function authorize.<locals>.newfunc at 0x7f81b8456840>
The documentation for wraps is really good, but basically when you wrap a function by default you lose the docstrings, and attributes, and all the rest. So you lose the app.route
decoration for your function, so Flask can't figure out how to build the URL.
By adding the wraps
decorator on there, you restore everything that app.route
did to your function, and Flask can create your route.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.