I use Django 2.2 and trying to detect if user is still connected when the user close his browser without logging out
I tried to use some Django packages like qsessions but it need to replace 'django.contrib.sessions.middleware.SessionMiddleware', with qsession middleware but it makes another error
django.contrib.sessions.middleware.SessionMiddleware not found
I need your help to get every user session separately.
Django sessions are not meant to be queried for their content. The user id in the session can be decoded from a session, but you need to iterate through all sessions:
from django.contrib.sessions.models import Session
from django.utils import timezone
def get_unexpired_sessions_for_user(user):
user_sessions = []
all_sessions = Session.objects.filter(expire_date__gte=timezone.now())
for session in all_sessions:
session_data = session.get_decoded()
if user.pk == session_data.get('_auth_user_id'):
user_sessions.append(session.pk)
return Session.objects.filter(pk__in=user_sessions)
This approach will work, but will not be performant when you have a lot of sessions in your database.
Related
basically, I want to allow an anonymous user to login to the website and not create a profile, but can save the session if wants, and revisit anytime
you can use django sessions.
You could use something like ...
from datetime import datetime
When they log in use this to start the session.
request.session['user'] = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
Then to check if the current user has a session go like this
if resquest.session.get('user'):
# then continue the session
if you want to end their session use
del request.session['user']
in installed apps in settings.py you need.
'django.contrib.sessions',
In your middleware you need
'django.contrib.sessions.middleware.SessionMiddleware',
So you need to check if there is a session started and if not start one.
For example in your home view or any other view at the start of the view for example you could have
if resquest.session.get('user'):
# Do whatever you need to do to continue the current session
else:
request.session['user'] = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
# Now you have started a new session. start doing what you need to do
I am currently using flask-login in my application for user login session management. I am using flask-sqlalchemy, so all working ok.
Because of my previous sql experience, I am not fan of ORM. I like to use SQL directly. May be it is because of my not sound knowledge in ORM. Anyways, my question is- is there any way I can use flask-login without ORM/flask-sqlalchemy, where I am getting user data by pymysql or MySQL-connector?
I know I can create sessions myself and pop when I logout, but I want to know if there is any way to use flask-login or any other session management library with pymysql?
I went with the following solution. It allows to redefine getting user from request Authorization header and use in stateless application.
from flask_login import login_required, LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
#login_manager.request_loader
def load_user_from_request(request):
api_key: str = request.headers.get('Authorization')
if api_key:
token_type, token = api_key.split()
print("token_type:" + token_type)
if token_type == "JWT" and token:
decoded_token: dict = decode_token(token)
username = decoded_token['identity']
user: User = get_user(username)
return user
return None
So if your endpoint is allowed to be used only by authorized users, #jwt_required or #login_required annotations can be used with method.
Be sure that route annotation is the first among others to guarantee correct work of other annotations; your endpoint can be look like:
#app.route('/api/users', methods=['GET'])
#login_required
#roles_required(['Admin']) # optional
def list_users():
return list[] # your code here
Here is another one annotation mentioned, #roles_required, it is not obligatory of course. Since Flask user management requires you to use ORM, you can overcome that by defining your own #roles_required annotation, see example here.
After i clear my browser history the session key and data that was added to the table django_session (session engine is database-backed by mysql) for the session remains and for subsequent requests a new 'session key' is added. In a situation where users clear their history frequently this table will grow inadvertently. Using clearsessions command doesn't remove the rows because the expiry date has not yet been reached. How do i overcome this issue if the expiry date is large? Is there some setting wrongly set up?
Actually, there is a way but highly inefficient since it requires iterating over all of the existing Sessions. You can use signals to catch post_save of Session model and then delete all of the existing Sessions of this user except the new one (I am not sure if this is what you want, because it will delete all of the sessions, not just the cleared one) .
from django.contrib.sessions.models import Session
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Session)
def save_session(sender, instance, **kwargs):
user_id = instance.get_decoded().get('_auth_user_id')
# Get all sessions excluding current session
sessions = Session.objects.exclude(session_key=instance.session_key)
# Iterate over all sessions and decode them
for session in sessions:
session_user_id = session.get_decoded().get('_auth_user_id')
# If the session belongs to user, delete it
if session_user_id == user_id:
session.delete()
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.
I have a python flask app using mongoengine and flask-security built up from the examples to expose all of the confirmation, registration, tracking, and recovery functionality.
Everything works except that a user created imperatively in the code using:
MongoEngineUserDatastore.create_user(...)
cannot login. That is, when you try to login with this user, you get an error message:
"Email requires confirmation"
Since the email with a hashed URL has not been sent, there is no way to confirm. Is there a parameter I can pass somewhere to confirm this user on creation or set the confirmed flag somewhere?
Here's my code:
I figured it out by confirming a newly registered user and examining mongodb to see what fields were added. Turns out that the required field for confirmation is confirmed_at, which must have a datetime so:
import datetime
# Create a user to test with
#app.before_first_request
def create_user():
user_datastore.create_user(
email='me#mydomain.com',
password=utils.encrypt_password('password'),
confirmed_at=datetime.datetime.now())
I've updated the gist here:
https://gist.github.com/davidthewatson/327776905ef30815c138
When you create your test user you need to make them active eg:
#app.before_first_request
def create_user():
user_datastore.create_user(
email='me#mydomain.com',
password=utils.encrypt_password('password'),
active=True)