I did not understand well using decorators in flasks and would like to use it to clean up my code.
Particularly, I don't understand if the decorator applied to an endpoint must return a view, that is passed to the template, or can be an arbitrary object that is then used in the function that will return a response for the endpoint.
Let me show by example.
I want to enable POST APIs and some endpoints only to authenticated users. I am using a oauth authentication library (flask-dance) that handle the login with Google.
I must use the credentials obtained by a successful log in to do some things, before passing the object user to the rest of the function of the endpoint.
I am doing something like this:
@app.route("/")
def index():
# get the response from the google authentications and do something
# if auth is successful, will return a user, if not, will redirect to a view
def work_on_user_auth(resp):
user = myClass.something(resp) // pseudo code
return user
// here I could not find a best approach than this: if auth fails, than redirect
if not google.authorized:
return redirect(url_for("google.login"))
try:
resp = get_user_auth()
except TokenExpiredError as e:
return redirect(url_for("google.login"))
user = work_on_user_auth(resp)
// and here will use by object user, based on the google auth, and eventually ship it to the view
return render_template('index.html', **user)
I am now copy pasting the logic in each endpoint, that check if user is logged via Oauth.
I would like to simplify, and use the work_on_user_auth(respFromGoogle) as a decorator for the endpoints: if successful, it must pass the object user, if not, a redirect will ask user to login.
I tried with something like this:
from functools import wraps
def logged_user_required(f):
@wraps(f)
def work_on_user_auth(self, *args, **kwargs):
// if not authorized or auth fails, redirect
if not google.authorized:
return redirect(url_for("google.login"))
try:
resp = get_user_auth()
except TokenExpiredError as e:
return redirect(url_for("google.login"))
print('user logged in', resp)
// if everything ok, create an object user and return it
return user
return work_on_user_auth
and would like to use it like that:
@app.route("/")
@logged_user_required
def index():
// here I want to access the `user` object from my decorated function, if failes, it will redirect
// how to:
user = logged_user_required // ??
return render_template('index.html', **user)
But getting different types of errors (last one: logged_user_required() missing 1 required positional argument: 'f')
Can you show the logic for getting a value returned by a decorated function, which, if fails, will tell the endpoint to redirect instead ?
Might there be a straight forward approach with flask-dance, good to know it, but I would like to have an answer to elucidate how to use decorators properly also in the future. Thanks!
Let's say you have user that determined somewhere outside view by
Google authMoon phase. And you want to pass this authenticated user into view.After that you want to do something inside view based on what user is passed.
So your code should be like:
This code will print:
In other way, if you don't need to know what is authenticated user inside
indexview, you may replace all check logic insidemoon_phased_authdecorator:In this case
indexdon't care about authentication.Abyssresponse will be returned to client beforeindexcall