python flask protect user page - python

i want to protect page on python-flask, can go on this page only limited users.
I'm write this code :
def im_seller():
if not g.user.seller_fee_paid:
return redirect(url_for('account.seller_fee'))
return
#account.route('/account/seller/products.html')
#login_required
#im_seller
def seller_products():
the script not working, give this error :
TypeError: im_seller() takes no arguments (1 given)
where I'm wrong ? thanks all.

Decorators take a function and need to return a function:
from functools import wraps
def require_seller(f):
#wraps(f)
def require_seller_wrapper(*args, **kwargs):
if not g.user.seller_fee_paid:
return redirect(url_for('account.seller_fee'))
return f(*args, **kwargs)
return require_seller_wrapper
You will also want to reverse the order of require_seller and login_required so you can be sure that g.user is set:
#account.route('/account/seller/products.html')
#require_seller
#login_required
def seller_products():
return "All the seller's products"
See this answer about decorators for all the details as to the whys.

from functools import wraps
def require_seller(f):
#wraps(f)
def require_seller_wrapper(*args, **kwargs):
if not g.user.seller_fee_paid:
return redirect(url_for('account.seller_fee'))
return f(*args, **kwargs)
return require_seller_wrapper
You should use the python decorator.Link

Related

Using a decorator with Django blocks the request

I'm trying to create my own decorator in order to validate a REST call with Django (using Django Rest Framework).
The decorator looks like this:
def allowed_states(allowed=[]):
def decorator(func):
def wrapper(self, request, *args, **kwargs):
print(func)
result = func(self, request, *args, **kwargs)
return result
return wrapper
return decorator
The request API looks something like this:
#swagger_auto_schema(
operation_id="my_api",
responses={
status.HTTP_204_NO_CONTENT: "",
}
)
#action(detail=True, methods=["DELETE"])
#allowed_states(allowed=["state1", "state2"])
def my_api(self, request, *args, **kwargs):
# do some stuff here
When my #allowed_states decorator is removed, the call works just fine. When I add it back I get a 404 error from Django framework saying it could not find a url pattern to execute for this call.
I tried removing self from wrapper (and from the func invoke as well).
Also I tried changing the decorators order above the function call.
Both didn't work.
The stack trace doesn't say much, merely that django could not find the url pattern:
Using the URLconf defined in
<code>my_project.urls</code>,
Django tried these URL patterns, in this order:
(and then the order of url patterns as they appear in my_project.urls)
Following a suggestion in the comments I used functools.wraps and that solved the problem:
from functools import wraps
def allowed_states(allowed=[]):
def decorator(func):
#wraps(func)
def wrapper(self, request, *args, **kwargs):
print(func)
result = func(self, request, *args, **kwargs)
return result
return wrapper
return decorator

Flask custom decorator not functioning as expected

I'm using Flask and have two decorators that I'm trying to use on certain routes to be more Pythonic, prevent code reuse, and improve readability.
The first of these are just checks to see if the user is logged in else redirect user to the login page. This works fine.
After this I check for the user 'class' (Admin, Manager, Standard User, etc), however this one isn't working and I'm not sure what is missing.
From the routes.py:
#app.route('/user/user-account.html', methods=['GET', 'POST'])
#login_required
def cna_account():
if valid_user() == True:
result = get_user_account()
return render_template('user/user-account.html', result=result)
else:
return redirect(url_for('index'))
#login_reqiured works fine, here is the code:
#wraps(f)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return f(*args, **kwargs)
else:
return redirect(url_for('index'))
return wrap
What I tried for the other decorator that doesn't work:
def valid_user(f):
''' Makes sure that only Base Users can view the Base User pages '''
#wraps(f)
def wrap(*args, **kwargs):
if 'access' in session and session['access'] == 'c':
return f(*args, **kwargs)
else:
return redirect(url_for('index'))
These are stored in a separate module that is imported in routes.py, the only thing I can guess is perhaps the session isn't being carried across even though it's included from flask in the module and routes, but again I'm not sure how this would be remedied.
What I'm trying to do with it is: have the routes that use both decorators and don't require the if valid_user() == True check. Instead it should function and look like:
#app.route('/user/user-account.html', methods=['GET', 'POST'])
#login_required
#valid_user
def cna_account():
result = get_user_account()
return render_template('user/user-account.html', result=result)
Any help on what I'm missing here? Do I need to pass the session variable as an argument to #valid_user? I tried that a few different ways and still had it throw errors.
Much appreciated!
You need to return the inner function wrap in valid_user:
def valid_user(f):
#wraps(f)
def wrap(*args, **kwargs):
if 'access' in session and session['access'] == 'c':
return f(*args, **kwargs)
return redirect(url_for('index'))
return wrap
While it is perfectly valid to not return anything from an outer decorator function, bear in mind that the wrapped function is passed to the wrapper at run time, thus, the returned value will be None:
def foo(f):
print("inside decorator with '{}'".format(f.__name__))
def inner():
return 10
#foo
def bar():
return 'in bar'
"inside decorator with 'bar'"
>>>bar()
Traceback (most recent call last):
File "", line 1, in
TypeError: 'NoneType' object is not callable

Python: how to make this more generic - probably with a decorator?

currently I have this code
#app.route("/protect1")
def protect1():
if not session.get('logged_in'):
session['next'] = "/protect1"
return render_template('login.html')
else:
return "This is the first protected page protect1"
#app.route("/protect2")
def protect2():
if not session.get('logged_in'):
session['next'] = "/protect2"
return render_template('login.html')
else:
return "This is the second protected page protect2"
in my flask app, everything working fine. Only it is not nice that I will need to repeat for each function (view) the if/else combination.
I would prefer to have some generic way, like this pseude-code:
#checklogin
#app.route("/protect1")
def protect1():
return "This is the first protected page protect1"
#checklogin
#app.route("/protect2")
def protect2():
return "This is the second protected page protect2"
One challenge here is that the #checklogin decorator would need to know the app.route path (e.g. "/protect1") in order to be able to set session['next'] correctly. I have no idea how to pass this parameter to the decorator, especially how to find it out in the first place. In other words, how does the function protect1() know that it is decorated with #app.route and which parameter ("/protect1") has been passed to that app.route decorator?
The decorator can look up the path on request; either using the URL that was loaded (available as request.url) or the request.endpoint attribute:
from functools import wraps
from flask import request, session
def checklogin(f):
#wraps(f)
def wrapper(*args, **kwargs):
if not session.get('logged_in'):
session['next'] = request.url
return render_template('login.html')
return f(*args, **kwargs)
return wrapper
Do place the decorator after the app.route() decorator or it'll not be registered as the handler for the route:
#app.route("/protect1")
#checklogin
def protect1():
return "This is the first protected page protect1"

Use decorators check user login in flask?

I defined a check user method:
from functools import wraps
def check_user(func):
#wraps(func)
def wrapper(*args, **kwargs):
if session['logged_in']:
return func(*args, **kwargs)
else:
return 'Log in'
return wrapper
#app.route('/test')
#check_user
def test():
return "Hello"
It does not work. how can I correct it?
It seems you don't know how to create decorators in python. There are many helpful answers on this question: How can I make a chain of function decorators in Python?
Below is how you can create a decorator that checks if a user is logged in.
from functools import wraps
def checkuser(func):
"""Checks whether user is logged in or raises error 401."""
#wraps(func)
def wrapper(*args, **kwargs):
if not g.user:
abort(401)
return func(*args, **kwargs)
return wrapper
The decorator above will raise a 401 error if a user is not logged in. It will return the view function otherwise.

Flask python assertion error: unimplemented method 'GET'

Can someone please explain to me the difference between these two blocks of code. The first one works while the latter throws the error which I've indicated in the title.
def login_required(method):
#functools.wraps(method)
def wrapper(*args, **kwargs):
if 'username' in flask.session:
return method(*args, **kwargs)
else:
flask.flash("A login is required to see the page!")
return flask.redirect(flask.url_for('index'))
return wrapper
AND
def login_required(method):
#functools.wraps(method)
def wrapper(*args,**kwargs):
if "username" in flask.session:
return method(*args,**kwargs)
else:
flask.flash("A login is required to see the page!")
return flask.redirect(flask.url_for('index'))
return wrapper
In the first code sample, you correctly return the wrapper function at the end of the login_required function.
In the second code sample you've got the return wrapper inside the wrapper function itself. Just de-dent that last line and you should be all set.

Categories

Resources