In my Flask Web-app, a new session is created whenever a new user logs in.
At the server-end, is there a way to track the currently active sessions?
If you are using Flask-Login for your user session management then is_authenticated property of Flask-login tells you if the user is logged in or not:
if not current_user.is_authenticated:
return current_app.login_manager.unauthorized()
If you want to protect your views you can use #login_required decorator. By default, when a user attempts to access a login_required view without being logged in, Flask-Login will flash a message and redirect them to the login view. (If the login view is not set, it will abort with a 401 error.)
#app.route("/settings")
#login_required
def settings():
pass
See the documentation
Related
I am using flask security for authentication what i want is when user access to a specific url without login/access then it redirects to login page but it redirects to home page.
I know if i add
#login_required
decorator then it will redirect to login page but how to do without that decorator.
i.e
#app.route('/result')
#roles_accepted('admin')
def result():
//some code
I read from flask documentation to add this in app config file.
SECURITY_UNAUTHORIZED_VIEW = '/login'
but again it does not redirect to login page.
Can anyone guide me what i am doing wrong here.
Flask-Security integrates a number of other extensions into a neat package, so it is possible to utilize those packages independently of Flask-Security if necessary.
If you've installed Flask-Security, you should also have Flask-Login installed as a dependency. You can use the current_user class from Flask-Login to check for authentication and redirect manually:
from flask import redirect
from flask_login import current_user
#app.route('/result')
#roles_accepted('/admin')
def result():
if not current_user.is_authenticated:
return redirect(url_for('.login'))
else:
some code....
I'm not sure how this will play with #roles_accepted, but based on the source code it looks like this decorator will intervene prior to the result function if an inappropriate role is used and handle it with the security_unauthorized_callback.
This actually seems to be similar to what #login_required does, i.e. call the security_unauthorized_callback function when the specified conditions are not met, in this case, the proper roles.
If I understand the #roles_required decorator correctly, the above solution should prevent any authenticated users of the improper role from accessing the results page, then manually redirect any unauthenticated users who make it past that check, without using the #login_required decorator.
What is happening is correct.
SECURITY_UNAUTHORIZED_VIEW = '/login'
Redirects the user to the login view, however, what appears to be happening is you have an authenticated user who is not authorized to access the view. When you redirect to the login page, since the user is already authenticated, another redirect happens to the SECURITY_POST_LOGIN_VIEW which in your case is home page.
I have two suggestions.
1) If unauthorized user attempts to access the protected view, log them out and add a flash message that they need to login as authorized users (that is assuming your SECURITY_POST_LOGOUT_VIEW is /login). In this case, your configuration becomes
SECURITY_UNAUTHORIZED_VIEW = '/logout'
and will achieve your objective of having the user redirected to the login page. This happens even if the current user is not authenticated (ie is anonymous/ not logged in)
2) Instead of logging out the user, retain the redirect to home page and add a flash message asking the user to login as an authorized user to access the resource
Our Django deployment checks every night which active users can still be found in out LDAP directory. If they cannot be found anymore, we set them to inactive. If they try to login next time, this will fail. Here is our code that does this:
def synchronize_users_with_ad(sender, **kwargs):
"""Signal listener which synchronises all active users without a usable
password against the LDAP directory. If a user cannot be
found anymore, he or she is set to “inactive”.
"""
ldap_connection = LDAPConnection()
for user in User.objects.filter(is_active=True):
if not user.has_usable_password() and not existing_in_ldap(user):
user.is_active = user.is_staff = user.is_superuser = False
user.save()
user.groups.clear()
user.user_permissions.clear()
maintain.connect(synchronize_users_with_ad)
But if they are still logged in, this session(s) is/are still working. How can we make them invalid immediately? All settings of the session middleware are default values.
You can log them out using
from django.contrib.auth import logout
if <your authentication validation logic>:
logout(request)
... from within any view.
logout() Django docs here.
In addition to the login_required decorator, you could use the user_passes_test decorator to test if the user is still active.
from django.contrib.auth import user_passes_test
def is_user_active(user):
return user.is_active
#user_passes_test(is_user_active, login_url='/your_login')
def your_function(request):
....
You can use a session backend that lets you query and get the sessions of a specific user. In these session backends, Session has a foreign key to User, so you can query sessions easily:
django-qsessions (based on django's db, cached_db session backends)
django-user-sessions (based on django's db session backend)
Using these backends, deleting all sessions of a user can be done in a single line of code:
# log-out a user
user.session_set.all().delete()
Disclaimer: I am the author of django-qsessions.
From the Flask-Login docs, it's described how a user of the system can require an authenticated User-model to access a method utilising the decorator syntax:
from flask_login import login_required
#app.route("/settings")
#login_required
def settings():
pass
Now that's all well and good, but I want to be able to examine if the user is authenticated in a method, something like this:
#app.route('/main/', methods=['GET', 'POST'])
main_route():
if request.method == 'GET':
if user_is_authenticated(): #Do the authentication here
#load authenticated /main/ html template etc.
pass
else:
#load unauthenticated /main/ html template etc.
pass
...
The reason for this, is because it factorises the GET and POST requests rather than duplicating routes for authenticated users and unauthenticated users.
How can I do this? Is it possible?
This is very simple in flask:
from flask_login import current_user
#app.route(...)
def main_route():
if current_user.is_authenticated:
return render_template("main_for_user.html")
else:
return render_template("main_for_anonymous.html")
See the documentation on anonymous users.
You could refer to the example here.
When the user has logged in, set session['logged_in']=True. At the same time, you can use Flask-login API to do some configurations in case that you want to use its functionality.
When you want to check whether the user has logged in manually rather than use the Flask-login API, then check the value of session['logged_in'].
I understand how to log a user in/out as well as authenticate within django, but one thing that is mission critical to a new project of mine.
I would like to have the user logged in (which I have), and I would like to then ask the user for their credentials again on certain pages.
I have one method through a EmployeeAuthenticatedMixin that I have made, which checks the POST data for the credentials. The main problem is the Mixin does not redirect, it merely serves up a page. So a user can hit the refresh button and resubmit the form, giving them access again.
Is there any way to ask for the user credentials and allow them access to the next page? Maybe an internal Django thing? Sessions? Messages?
You can log them out forcing them to log back in, using request(logout)
pseudo-coded
def confirm_crednetials(request)
logout(request)
render 'form'
or First prompt the user with a form if they do not have a cookie, you can check and set the cookie with this built in django method resp.set_cookie(foo, cookie) but after you authenticate the user.
if 'id' in request.COOKIES:
**render page
else:
authenticate_user(username=foo, password=bar)
resp.set_cookie(foo, cookie)
I wrote a signal that would fire after login:
from django.contrib.auth.signals import user_logged_in
import datetime
def reauthentication(sender, user, request, **kwargs):
request.session['last_login_time'] = str(datetime.datetime.now())
request.session.save()
user_logged_in.connect(reauthentication)
Then I wrote middleware to catch views that require reauthentication if the sessions last_login_time is older than 3 minutes.
Using Django-facebook for the first time.
For some reason, if i log in with facebook, but later log out of my Facebook account. My application stays logged in with the default Django user, with an expired session token because "the user has logged out". If I then re-log in to facebook, the Django app stays "logged out" of Facebook.
In the case above, I have tried attaching #facebook_required_lazy to the top of my view function, but to no effect. What is the intended behavior of this decorator in this use case? The view contains a call to get_persistent_graph.
Your Django login session is completely independent from your Facebook login session. Facebook is used to authenticate only, that is at the time of the login. But the login sessions are independent, not connected. Thus, logging out from Facebook does not affect your Django session at all. It is normal that you are still logged in on Django.
To logout from Django you need to use the logout method of the Django framework, in module django.contrib.auth, for example with a custom logout method like this:
from django.contrib.auth import logout as django_logout
def logout(request):
django_logout(request)
return some_other_view(request)