I know this is a possible duplicate post, I found a solution for this, but those posts are from older versions of Django and I can't get the new syntaxis. Could someone give me a tip please?
I'm trying to prevent users to use the same account simultaneously. So when someone log in an account, if the user and pass are ok, I'm iterating the django_session table in order to find if theres any other session with the same account, if yes, close this session and start the last one.
After auth.authenticate(blah blah):
if user is not None:
# Checks if there's any other active session with the same account
for session in Session.objects.filter(session_key=request.session.session_key): # //aq
data = session.get_decoded()
print(data.get('_auth_user_id', None))
if data.get('_auth_user_id', None) == str(user.id):
session.delete()
But something is not working with this syntaxis.
I can't get the session user's ID.
When a user logs in I'm using request.session['logueado'] = user.id and auth.login(request, user).
This should be like a "last to log in wins" system.
EDIT: Whole code:
def login(request):
if 'logged' in request.session:
return redirect(main)
if request.method == "GET":
form = LoginForm
return render(request, "login.html", {"form": form})
if request.method == "POST":
print('POST method.')
form = LoginForm(request.POST)
if form.is_valid():
print('Valid form.')
user_name = form.cleaned_data.get('username')
user_pass = form.cleaned_data.get('password')
user = auth.authenticate(username=user_name, password=user_pass)
if user is not None:
for session in Session.objects.filter(session_key=request.session.session_key):
print('Hello')
data = session.get_decoded()
if data.get('_auth_user_id', None) == request.session.session_key:
print('Same account in more than 1 session.')
session.delete()
#------------------------------------------------------------------
request.session['logged'] = user.id
print(request.session['logged'])
auth.login(request, user)
request.session.set_expiry(0) #
return redirect(main)
else:
return render(request, "loginError.html", {"form": form})
EDIT: Definitive solution: (Thank you Daniel Roseman!)
user = auth.authenticate(username=user_name, password=user_pass)
if user is not None:
# Checks if there's another session with the same acc
Sessions = Session.objects.all()
for row in Sessions:
print(row.get_decoded().get('_auth_user_id'))
print(user.id)
if str(row.get_decoded().get("_auth_user_id")) == str(user.id):
print('Same sessions')
row.delete()
request.session['logged'] = user.id
Your code is based on all sorts of false assumptions.
Session keys don't in any way map to login IDs. And they are unique: each client will have a different key, even if they're logged in as the same user. What's more, the session is explicitly flushed when a user logs in, so they will get a new key.
In other words, the only way to do something like this would be to iterate over all sessions in the database, decode them, and check if their _auth_user_id item is equal to the user ID.
As Daniel Roseman answered, you can iterate over all sessions in DB, decode all of them, and delete those you want. But it's slow, particularly if your site has high traffic and there are lots of sessions.
If you need a faster solution, 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 don't need to iterate over all session objects:
django-user-sessions (based on django's db session backend)
django-qsessions (based on django's cached_db session backend)
Using these backends, deleting all sessions of a user can be done in a single line of code:
user.session_set.all().delete()
Disclaimer: I am the author of django-qsessions.
Related
i have a problem with a functionality of flask-login.
I need to create a system, that prevents multiple users from logging in on one account in the same time. The goal i am trying to achieve, is a way to check if the user is currently logged in, and deny access to people that are trying to log in if the account is already logged in. I was trying to use:
user.is_active
user.is_authenticated
But they always are displaying "True", here is the rest of the code: is there a property that changes after the users logs in/out?
def login():
if request.method == 'GET':
return render_template('login.html')
else:
login = request.form['login']
password = request.form['password'].encode('utf-8')
user = User.query.filter_by(username=f"{login}").first()
if user == None:
return "Non-Existing User"
else:
if bcrypt.checkpw(password,user.password.encode('utf-8')):
login_user(user)
return "Success"
else:
return "Bad creds."
#app.route('/logout')
#login_required
def logout():
logout_user()
return 'You are logged out'```
I don't know about any property but we can do it another way. You can store a token like thing in database with the user details.
class user(db.Model):
[...]
token = db.Column(db.String(20))
when the user login, you can generate a random hex or string and store it in database.
When user logout set token to False
while logging in the user , you can check if token is not False.
user = User.query.filter_by(username=user_input).first()
if user.token != False:
// allow user to login
else:
// don't allow him and show warning message.
I want to use django's default password reset view "PasswordResetView" which let's the user reset his password when he forgets it in a template that already has a view that i built on my own, after looking at the tutorials and the questions i found how to use it only on a different template that is made only for the password reset, but i don't want the user to go to a different page just to change his password when he forgets it, i want to make it in a bootstrap modal in the home page.
here is my home view that i want to add PasswordResetView functionality to it:
def home(request):
user = request.user
signin_form = SigninForm()
signup_form = SignupForm()
if request.method == "POST":
if 'signin_form' in request.POST:
signin_form = SigninForm(request.POST)
if signin_form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user:
login(request, user)
elif user is None:
messages.error(request, 'ُEmail or password is incorrect')
if 'signup_form' in request.POST:
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
signup_form.save()
full_name = signup_form.cleaned_data.get('full_name')
email = signup_form.cleaned_data.get('email')
raw_password = signup_form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
context = {'signin_form': signin_form,'signup_form': signup_form}
return render(request, 'main/home.html', context)
PS: i tried copy pasting the source code of that view (PasswordResetView) from django's source code in my view but i found some errors because it's a class based view, so if you find this the proper way, guide me to do it
or if i can't merge them somehow how to create a custom one
this is what i found in the other answers which lets you use it in a certain template that has only that view (PasswordResetView) which is not what i want:
from django.contrib.auth import views as auth_views
path('password_reset/', auth_views.PasswordResetView.as_view(template_name="myapp/mytemplate.html",form_class=mypasswordresetform),name="reset_password"),
I'll give you a simple approach to having a password reset feature on your django application. Before having any code, let me give a brief exlanation of the process. What you want to do is get a user to input their email, check if there is any user with that email, then if there is one, send an email to that address with a uniquely generated link.
From this link, you should be able to extract the user object which you need to change password. An example would be to use django's signing module. This link will simply need to redirect the user to a template where there is a form with 2 fields i.e. New Password and Verify Password.
Django's generic views come with this functionality out-of-the-box if you are using Django's authentication module, but you aren't forced to use it, but its best to do so.
Here I'll only show you how to collect the email address on the same view as you said you wanted.
def home(request):
# ...your other code
if request.method == 'post':
if 'reset_password' in request.POST:
email = request.POST.get("email", "")
user_qs = User.objects.filter(email=email)
if not user_qs.exists():
# send error message to user here
else:
user = user_qs.get()
# send email with uniquely generated url here.
The other aspects of generating a URL and sending the mail, I believe you can research these separately. But I hope you now have an idea of where and what to search.
I am writing a web app using Django. I am trying to allow a user to see its profile and only his own.
if(not request.user.id == request.GET.get('user_id', '')):
raise PermissionDenied
My question is: is it safe to check this way or is it possible for a smart kid to somehow alter the value in request.user.id to match the user_id of anyone?
The user must be logged in before accessing this page using this:
user = LDAPBackend().authenticate(username=username, password=password)
if(user is not None):
login(request, user)
Yes it should be safe.
request.user get's only populated when authentication with session cookies. Unless and until someone steals the cookie or token it should be no issue.
One thing i don't understand is why do you need user_id parameter here to be explicitly passed.
if you are putting logged in compulsory to view the page. there are two way i can see this.
/profile
Directly get user profile corresponding to the request.user
/<username>
Query the profile corresponding to the username and compare it with request.user.id
request.user is set using AuthenticationMiddleware for each request:
Adds the user attribute, representing the currently-logged-in user, to every incoming HttpRequest object.
If a user is not logged in then request.user is set to Anonymous User. Have a look at Authentication in Web requests.
So, I am not sure how would a smart kid alter the id of the logged-in user.
Mostly, there is a one-to-one relation between the user and its profile. If that's the case you can modify the queryset to get the profile for request.user directly.
request.user is already an object about the current user who send the request to get the page. You can use login_required or to only allow user login to access (2 solutions : decorator or Mixin).
And then you can use your condition to load the page in the function. Example:
=> url.py:
url(r'^profile/$', login_required(app.views.profile), name='profile'),
=> views.py :
def profile(request):
try:
myProfile = User.objects.get(username=request.user.username)
except ObjectDoesNotExist:
return render(request, "error.html", {'message' : 'No Profile Found'})
return render(request, "app/profile.html",
{'myProfile': myProfile})
Like this you can only display YOUR profile (user who send the request) AND you need to be logged.
EDIT: if you don't want "try and catch" you can use get_object_or_404(User, username=request.user.username)
I hit a problem when get session_key from request.session.
I am using Django1.8 and Python2.7.10 to set up a RESTful service.
Here is snippet of my login view:
user = authenticate(username=userName, password=passWord)
if user is not None:
# the password verified for the user
if user.is_active:
# app_logger.debug("User is valid, active and authenticated")
if hasattr(user, 'parent') :
login(request, user)
request.session['ut'] = 4
# user type 1 means admin, 2 for teacher, 3 for student, 4 for parents
request.session['uid'] = user.id
description = request.POST.get('description','')
request.session['realname'] = user.parent.realname
request.session['pid'] = user.parent.id
devicemanage.update_user_device(devicetoken, user.id, ostype, description)
children = parentmanage.get_children_info(user.parent.id)
session_id = request.session.session_key
user.parent.login_status = True
user.parent.save()
return JsonResponse({'retcode': 0,'notify_setting':{'receive_notify':user.parent.receive_notify,'notify_with_sound':user.parent.notify_with_sound,'notify_sound':user.parent.notify_sound,'notify_shake':user.parent.notify_shake},'pid':user.parent.id,'children':children,'name':user.parent.realname,'sessionid':session_id,'avatar':user.parent.avatar,'coins':user.parent.coins})
Now when this function is called, I see sometimes session_id is None within the response.
So, after debugging (I set breakpoint at the return JsonResponse(...) line), I see that when I hit the breakpoint the request.session._session_key is None, but request.session.session_key is u'j4lhxe8lvk7j4v5cmkfzytyn5235chf1' and session_id is also None.
Does anyone know how can this happen? Why isn't the value of session_key set when assigning it to session_id before returning the response?
According to John's suggestion.
I fixed the problem by this snippet:
if not request.session.session_key:
request.session.save()
session_id = request.session.session_key
As per documentation:
SessionStore.create() is designed to create a new session (i.e. one
not loaded from the session store and with session_key=None). save()
is designed to save an existing session (i.e. one loaded from the
session store). Calling save() on a new session may also work but has
a small chance of generating a session_key that collides with an
existing one. create() calls save() and loops until an unused
session_key is generated.
Means it is safer to use create() instead of save(). So you can try like this:
if not request.session.session_key:
request.session.create()
session_id = request.session.session_key
The problem is when user tries 'forgot password' option. It creates new reset_key for verification, but the new key is not getting updated into DB.
#app.route('/login/forgot/', methods=['GET', 'POST'])
def forgot():
form = ResetLoginForm(request.form)
#There's no session yet. User just pointing to /login/forgot url.
if request.method == 'POST' and form.validate():
user = User.query.filter_by(email=form.email.data).first()
if not user:
flash('The username or email incorrect')
return render_template('forgot.html', form=form)
reset_key = generate_key() ## this creates a new key, but how update this key into db?
#tried something like
user.reset_key = reset_key
db.session.add(user)
db.session.commit()
#this is not working. Is it due to session is not started or something?
Thanks for any help or hint.
This is because User.query.filter_by(email=form.email.data).first() will return a sqlalchemy.orm.query.Query object. As its doc says:
Query is the source of all SELECT statements generated by the ORM,
both those formulated by end-user query operations as well as by high
level internal operations such as related collection loading. It
features a generative interface whereby successive calls return a new
Query object, a copy of the former with additional criteria and
options associated with it.
So you just get a copied object, so your change will not work;
You can use like this:
user = db.session.query(User).filter_by(email==form.email.data).first()
and then you can change user attrs
user = db.session.query(User).first() solved problem.