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!
To understand why you need
wraps
, you can do this:Once with wraps, and once without. With wraps, you'll see something like this:
Without it, you'll see:
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 thatapp.route
did to your function, and Flask can create your route.