Best way to make Flask-Login's login_required the default
Question:
Like this question: Best way to make Django's login_required the default
I’m using Flask-Login
‘s login_required decorator now. Is there anyway to make it the default behavior in Flask
?
Answers:
I did this in my instruments project. I use the before_request
decorator:
@app.before_request
def check_valid_login():
login_valid = 'user' in session # or whatever you use to check valid login
if (request.endpoint and
'static' not in request.endpoint and
not login_valid and
not getattr(app.view_functions[request.endpoint], 'is_public', False) ) :
return render_template('login.html', next=request.endpoint)
and I then created an is_public()
decorator for the few places that would need to be accessible without login:
def public_endpoint(function):
function.is_public = True
return function
If you are using blueprints and need to protect an entire blueprint with a login, you can make the entire before_request
to require login.
This is what I use for my CMS blueprint:
@cms.before_request
@login_required
def before_request():
if g.user.role != ROLE_ADMIN:
abort(401)
If you need only to check if the user is logged in (and not if the user has privileges) you can simply pass
the function
This is a follow up ( bit more pythonic but thats debatable ) to @MalphasWats
already great answer.
Also includes an important security fix suggested by @nonagon.
Explanation of the vulnerability with 'static' in request.endpoint
:
Imagine that there is route which can be user defiened in some way, like a profile link for example.
If the user sets his name lets say Static Joe, then:
"Static Joe" --slugifys--> /usr/profiles/static_joe
.
This way making this route public. This is just asking for trouble.
Here is the route guard function which is appened before every request handling:
@app.before_request
def check_route_access():
if any([request.endpoint.startswith('static/'),
current_user.is_authenticated, # From Flask-Login
getattr(app.view_functions[request.endpoint],'is_public',False)]):
return # Access granted
else:
return redirect(url_for('users.login_page'))
( Flask-Login is an excellent module and makes session handling a breeze )
And here is the decorator ( @public_route ) which you can use to allow access to special pages that need public access by default. (register page, login page):
def public_route(decorated_function):
decorated_function.is_public = True
return decorated_function
I had to secure a REST API and I have solved finally like this:
@app.before_request
@auth.login_required
def login_required_for_all_request():
pass
(Actually I used also the connexion framework so I had to use: @app.app.before_request )
Like this question: Best way to make Django's login_required the default
I’m using Flask-Login
‘s login_required decorator now. Is there anyway to make it the default behavior in Flask
?
I did this in my instruments project. I use the before_request
decorator:
@app.before_request
def check_valid_login():
login_valid = 'user' in session # or whatever you use to check valid login
if (request.endpoint and
'static' not in request.endpoint and
not login_valid and
not getattr(app.view_functions[request.endpoint], 'is_public', False) ) :
return render_template('login.html', next=request.endpoint)
and I then created an is_public()
decorator for the few places that would need to be accessible without login:
def public_endpoint(function):
function.is_public = True
return function
If you are using blueprints and need to protect an entire blueprint with a login, you can make the entire before_request
to require login.
This is what I use for my CMS blueprint:
@cms.before_request
@login_required
def before_request():
if g.user.role != ROLE_ADMIN:
abort(401)
If you need only to check if the user is logged in (and not if the user has privileges) you can simply pass
the function
This is a follow up ( bit more pythonic but thats debatable ) to @MalphasWats
already great answer.
Also includes an important security fix suggested by @nonagon.
Explanation of the vulnerability with 'static' in request.endpoint
:
Imagine that there is route which can be user defiened in some way, like a profile link for example.
If the user sets his name lets say Static Joe, then:
"Static Joe" --slugifys--> /usr/profiles/static_joe
.
This way making this route public. This is just asking for trouble.
Here is the route guard function which is appened before every request handling:
@app.before_request
def check_route_access():
if any([request.endpoint.startswith('static/'),
current_user.is_authenticated, # From Flask-Login
getattr(app.view_functions[request.endpoint],'is_public',False)]):
return # Access granted
else:
return redirect(url_for('users.login_page'))
( Flask-Login is an excellent module and makes session handling a breeze )
And here is the decorator ( @public_route ) which you can use to allow access to special pages that need public access by default. (register page, login page):
def public_route(decorated_function):
decorated_function.is_public = True
return decorated_function
I had to secure a REST API and I have solved finally like this:
@app.before_request
@auth.login_required
def login_required_for_all_request():
pass
(Actually I used also the connexion framework so I had to use: @app.app.before_request )